I have Tag models that have an attribute is_obsolete (default set to False)
class Tag(model.Model):
...
is_obsolete = False
I have StatusInfo models that have a foreign key to Tag through "affected_tag".
class StatusInfo(models.Model):
...
affected_tag = ForeignKey(Tag)
When the StatusInfo instance is created they fire off the pre_save()
signal to change <StatusInfo>.affected_tag.is_obsolete=True
@receiver(pre_save, sender=StatusInfo)
def status_change_modification(sender, instance, *args, **kwargs):
"""
Changes tags and concepts to be obsolete or deprecated.
if a tag is obsolete or deprecated, all of the tag's concepts are obsolete or deprecated
"""
assert hasattr(instance.affected_tag, "id")
# set up variables
kwargs = {}
if instance.status == "d":
kwargs["is_deprecated"] = True
elif instance.status == "o":
kwargs["is_obsolete"] = True
inner_tag_status_change(instance, **kwargs)
def inner_tag_status_change(instance, **kwargs):
"""
update the is_updated fields for status_info
kwargs is either:
kwargs = {'is_obsolete': True} # or {'is_deprecated': True}
"""
affected = Tag.objects.filter(id=instance.affected_tag.id).first()
affected.__dict__.update(**kwargs)
affected.save(update_fields=list(kwargs.keys()))
What I can't figure out is why when this hits the bottom of the test I still have my Tag instance self.soon_to_be_obsolete_tag.is_obsolete == False
I've tried .update(**kwargs)
and .save(updated_fields=list(kwargs.keys()))
inside inner_tag_status_change() but it doesn't save the changes
It looks good when stepping through it in debug mode then it reverts back for the last line of the test. Am I working on a separate copy or is caching a thing that I should be checking?
def test_status_set_tag_info_obsolete(self):
""" check to see if the creation of a statusInfo
object which runs a pre_save signal changes
the soon_to_be_obsolete_tag to is_obsolete=True
"""
self.assertFalse(self.soon_to_be_obsolete_tag.is_obsolete)
self.main_status_info = StatusInfoFactory(
affected_tag=self.soon_to_be_obsolete_tag,
status="o", # obsolete
by=self.new_replacement_tag,
)
self.assertTrue(self.soon_to_be_obsolete_tag.is_obsolete) # still False
Based on your test and your pre-save logic, it looks like you're updating the tag in the database but Django's cache of that tag object that attached to your model isn't be updated.
So I believe the issue is that in both status_change_modification
and inner_tag_status_change
, you accessed instance.affected_tag
, but you didn't update instance.affected_tag
directly. Instead you grabbed that tag from the database with an extra query and then saved it.
I would guess that if you updated your test to this, it would work:
self.assertTrue(Tag.objects.get(id=self.soon_to_be_obsolete_tag).is_obsolete)
Or if you used refresh_from_db
to force a refresh on self.soon_to_be_obsolete_tag
that should work too:
self.soon_to_be_obsolete_tag.refresh_from_db()
self.assertTrue(self.soon_to_be_obsolete_tag.is_obsolete)
You might also consider updating your inner_tag_status_change
logic to update the tag directly too (I'm not certain whether this would fix the issue you're experiencing but it would remove an extra SELECT
query that may not be needed):
def inner_tag_status_change(instance, **kwargs):
instance.affected_tag.__dict__.update(**kwargs)
instance.affected_tag.save(update_fields=list(kwargs.keys()))