简体   繁体   中英

Django - NullBooleanField won't retain False value from custom save() method

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.

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.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM