Skip to content

Commit 8b60451

Browse files
authored
Fix #498 -- Reset GFK fields when content object is None (#499)
1 parent 2121a08 commit 8b60451

File tree

4 files changed

+38
-11
lines changed

4 files changed

+38
-11
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
### Changed
13+
- Reset `content_type` and `object_id` fields when the content object is `None`
1314

1415
### Removed
1516

model_bakery/baker.py

+17-11
Original file line numberDiff line numberDiff line change
@@ -695,21 +695,27 @@ def _handle_m2m(self, instance: Model):
695695
def _handle_generic_foreign_keys(self, instance: Model, attrs: Dict[str, Any]):
696696
"""Set content type and object id for GenericForeignKey fields."""
697697
for field_name, data in attrs.items():
698-
content_type_field = data["content_type_field"]
699-
object_id_field = data["object_id_field"]
698+
ct_field_name = data["content_type_field"]
699+
oid_field_name = data["object_id_field"]
700700
value = data["value"]
701701
if is_iterator(value):
702702
value = next(value)
703703
if value is None:
704-
continue
705-
706-
setattr(instance, field_name, value)
707-
setattr(
708-
instance,
709-
content_type_field,
710-
contenttypes_models.ContentType.objects.get_for_model(value),
711-
)
712-
setattr(instance, object_id_field, value.pk)
704+
# when GFK is None, we should try to set the content type and object id to None
705+
content_type_field = instance._meta.get_field(ct_field_name)
706+
object_id_field = instance._meta.get_field(oid_field_name)
707+
if content_type_field.null:
708+
setattr(instance, ct_field_name, None)
709+
if object_id_field.null:
710+
setattr(instance, oid_field_name, None)
711+
else:
712+
setattr(instance, field_name, value)
713+
setattr(
714+
instance,
715+
ct_field_name,
716+
contenttypes_models.ContentType.objects.get_for_model(value),
717+
)
718+
setattr(instance, oid_field_name, value.pk)
713719

714720
def _remote_field(
715721
self, field: Union[ForeignKey, OneToOneField]

tests/generic/models.py

+10
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,16 @@ class DummyGenericForeignKeyModel(models.Model):
295295
class DummyGenericRelationModel(models.Model):
296296
relation = GenericRelation(DummyGenericForeignKeyModel)
297297

298+
class GenericForeignKeyModelWithOptionalData(models.Model):
299+
content_type = models.ForeignKey(
300+
contenttypes.ContentType, on_delete=models.CASCADE, blank=True, null=True
301+
)
302+
object_id = models.PositiveIntegerField(blank=True, null=True)
303+
content_object = GenericForeignKey("content_type", "object_id")
304+
305+
class GenericRelationModelWithOptionalData(models.Model):
306+
relation = GenericRelation(GenericForeignKeyModelWithOptionalData)
307+
298308

299309
class DummyNullFieldsModel(models.Model):
300310
null_foreign_key = models.ForeignKey(

tests/test_filling_fields.py

+10
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,16 @@ def test_with_fill_optional(self):
374374
assert isinstance(dummy.content_type, ContentType)
375375
assert dummy.content_type.model_class() is not None
376376

377+
def test_with_fill_optional_but_content_object_none(self):
378+
dummy = baker.make(
379+
models.GenericForeignKeyModelWithOptionalData,
380+
content_object=None,
381+
_fill_optional=True,
382+
)
383+
assert dummy.content_object is None
384+
assert dummy.content_type is None
385+
assert dummy.object_id is None
386+
377387

378388
@pytest.mark.django_db
379389
class TestFillingForeignKeyFieldWithDefaultFunctionReturningId:

0 commit comments

Comments
 (0)