Django: Return 'none' From Onetoonefield If Related Object Doesn't Exist?
Solution 1:
This custom django field will do exactly what you want:
classSingleRelatedObjectDescriptorReturnsNone(SingleRelatedObjectDescriptor):
def__get__(self, *args, **kwargs):
try:
returnsuper(SingleRelatedObjectDescriptorReturnsNone, self).__get__(*args, **kwargs)
except ObjectDoesNotExist:
returnNoneclassOneToOneOrNoneField(models.OneToOneField):
"""A OneToOneField that returns None if the related object doesn't exist"""
related_accessor_class = SingleRelatedObjectDescriptorReturnsNone
To use it:
classBreakfast(models.Model):
pass# other fieldsclassEgg(m.Model):
breakfast = OneToOneOrNoneField(Breakfast, related_name="egg")
breakfast = Breakfast()
assert breakfast.egg == None
Solution 2:
I just ran into this problem, and found an odd solution to it: if you select_related(), then the attribute will be None if no related row exists, instead of raising an error.
>>>print Breakfast.objects.get(pk=1).egg
Traceback (most recent call last):
...
DoesNotExist: Egg matching query does not exist
>>>print Breakfast.objects.select_related("egg").get(pk=1).egg
None
I have no idea if this can be considered a stable feature though.
Solution 3:
I know that on ForeignKey you can have null=True
when you want to allow the model not to point to any other model. OneToOne is only a special case of a ForeignKey:
classPlace(models.Model)
address = models.CharField(max_length=80)
classShop(models.Model)
place = models.OneToOneField(Place, null=True)
name = models.CharField(max_length=50)
website = models.URLField()
>>>s1 = Shop.objects.create(name='Shop', website='shop.com')
>>>print s1.place
None
Solution 4:
Django 1.10 solution as by Fedor at accepted answer:
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.fields.related import OneToOneField
from django.db.models.fields.related_descriptors import ReverseOneToOneDescriptor
classReverseOneToOneOrNoneDescriptor(ReverseOneToOneDescriptor):
def__get__(self, instance, cls=None):
try:
returnsuper(ReverseOneToOneOrNoneDescriptor, self).__get__(instance=instance, cls=cls)
except ObjectDoesNotExist:
returnNoneclassOneToOneOrNoneField(models.OneToOneField):
"""A OneToOneField that returns None if the related object doesn't exist"""
related_accessor_class = ReverseOneToOneOrNoneDescriptor
Solution 5:
OmerGertel did already point out the null
option. However, if I understand your logical model right, then what you actually need is a unique and nullable foreign key from Breakfast to Egg. So a breakfast may or may not have an egg, and a particular egg can only be associated with one breakfast.
I used this model:
classEgg(models.Model):
quality = models.CharField(max_length=50)
def__unicode__(self):
return self.quality
classBreakfast(models.Model):
dish = models.TextField()
egg = models.ForeignKey(Egg, unique=True, null=True, blank=True)
def__unicode__(self):
return self.dish[:30]
and this admin definition:
classEggAdmin(admin.ModelAdmin):
passclassBreakfastAdmin(admin.ModelAdmin):
pass
admin.site.register(Egg, EggAdmin)
admin.site.register(Breakfast, BreakfastAdmin)
Then I could create and assign an egg in the edit page for a breakfast, or just do not assign one. In the latter case, the egg property of the breakfast was None. A particular egg already assigned to some breakfast could not be selected for another one.
EDIT:
As OmerGertel already said in his comment, you could alternatively write this:
egg = models.OneToOneField(Egg, null=True, blank=True)
Post a Comment for "Django: Return 'none' From Onetoonefield If Related Object Doesn't Exist?"