Reputation: 2006
Newcomer to Django, so forgive me if I'm missing something obvious or doing something stupid here...
I have a Django model with a custom save() extension. Trimming the unrelated fields and methods, it looks like this:
class Content(models.Model):
url = models.URLField(max_length=1000)
image = models.URLField(blank=True, max_length=1000)
image_type = models.NullBooleanField(default=None)
def save(self, *args, **kwargs):
if self.url:
img, img_type = image_extractor(self.url)
print 'extractor returned: ', img_type
print 'before set: ', self.image_type
setattr(self, 'image', img)
setattr(self, 'image_type', img_type)
print 'after set: ', self.image_type
super(Content, self).save(*args, **kwargs)
print 'from query: ', Content.objects.get(url=self.url).image_type
The image_extractor function returns a url string and a boolean value representing the image type: True for images larger than a certain width, False for smaller images, or None if no suitable image was found. The problem is, when I query Content.objects and check image_type, all objects return either True or None. Hence the print statements. The images with image_type None or True work as expected, but when image_type is returned False, this is what prints:
extractor returned: False
before set: None
after set: False
from query: True
Somehow the call to super().save always reverts image_type to True if I try to set False (but not if I set None). I admit, I don't understand super() very well, but based on the documentation it seems to be necessary when extending the model function. Can anyone explain what's going on here, and how I can fix it?
Edit: I notice that I can change the value to False through the admin page and it stays False. But I still need to fix the save() method. For now, I have just replaced the boolean field with an integer field and saved values as 0 or 1, which does work. But I'd still like to know why the more appropriate field doesn't.
Upvotes: 1
Views: 1332
Reputation: 2006
Since writing this question, I had moved ahead with a temporary solution of using an IntegerField to store the boolean as 0 or 1. Upon deciding to revisit the problem tonight and switching back to the NullBooleanField, suddenly everything works as intended. So it seems danodonovan was correct: the code above is correct, and unfortunately I still have no idea what was causing the error. Something else I changed while using the IntegerField must have resolved the issue. Thanks to those of you who have taken a look and offered some opinions, and I'm sorry to have wasted your time.
Upvotes: 1
Reputation: 301
the way you overload save method looks good. I think you are not loading the good object from database. Use the primary key will probably works better.
In your case just replace that:
Content.objects.get(url=self.url).image_type
by that:
Content.objects.get(pk=self.pk).image_type
Looks at the documentation: https://docs.djangoproject.com/en/dev/ref/models/instances/#the-pk-property
Extract from the django documention:
Once the object has been saved, you must reload the object in order to access the actual value that was applied to the updated field:
product = Products.objects.get(pk=product.pk)
print(product.number_sold)
Upvotes: 0