12π
This custom django field will do exactly what you want:
class SingleRelatedObjectDescriptorReturnsNone(SingleRelatedObjectDescriptor):
def __get__(self, *args, **kwargs):
try:
return super(SingleRelatedObjectDescriptorReturnsNone, self).__get__(*args, **kwargs)
except ObjectDoesNotExist:
return None
class OneToOneOrNoneField(models.OneToOneField):
"""A OneToOneField that returns None if the related object doesn't exist"""
related_accessor_class = SingleRelatedObjectDescriptorReturnsNone
To use it:
class Breakfast(models.Model):
pass
# other fields
class Egg(m.Model):
breakfast = OneToOneOrNoneField(Breakfast, related_name="egg")
breakfast = Breakfast()
assert breakfast.egg == None
9π
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.
- [Django]-Python-social-auth AuthCanceled exception
- [Django]-How to render menu with one active item with DRY?
- [Django]-How can I change the modelform label and give it a custom name
5π
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:
class Place(models.Model)
address = models.CharField(max_length=80)
class Shop(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
- [Django]-How to implement breadcrumbs in a Django template?
- [Django]-How to remove white space from html source code
- [Django]-Django template how to look up a dictionary value with a variable
2π
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
class ReverseOneToOneOrNoneDescriptor(ReverseOneToOneDescriptor):
def __get__(self, instance, cls=None):
try:
return super(ReverseOneToOneOrNoneDescriptor, self).__get__(instance=instance, cls=cls)
except ObjectDoesNotExist:
return None
class OneToOneOrNoneField(OneToOneField):
"""A OneToOneField that returns None if the related object doesn't exist"""
related_accessor_class = ReverseOneToOneOrNoneDescriptor
- [Django]-Sortable table columns in django
- [Django]-How does manage.py work?
- [Django]-How to filter objects for count annotation in Django?
1π
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:
class Egg(models.Model):
quality = models.CharField(max_length=50)
def __unicode__(self):
return self.quality
class Breakfast(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:
class EggAdmin(admin.ModelAdmin):
pass
class BreakfastAdmin(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)
- [Django]-Slow MySQL "INNER JOIN"
- [Django]-Why doesn't CeleryCAM work with Amazon SQS?
- [Django]-How to go from django image field to PIL image and back?
0π
I would recommend using try
/ except Egg.DoesNotExist
whenever you need to access Breakfast.egg
; doing so makes it very clear whatβs going on for people reading your code, and this is the canonical way of handling nonexistent records in Django.
If you really want to avoid cluttering your code with try
/ except
s, you could define a get_egg
method on Breakfast
like so:
def get_egg(self):
""" Fetches the egg associated with this `Breakfast`.
Returns `None` if no egg is found.
"""
try:
return self.egg
except Egg.DoesNotExist:
return None
This will make it clearer to people reading your code that eggs are derived, and it may hint at the fact that a lookup gets performed when one calls Breakfast.get_egg()
.
Personally, Iβd go for the former approach in order to keep things as clear as possible, but I could see why one may be inclined to use the latter approach instead.
- [Django]-Proper way to bulk_create for ManyToMany field, Django?
- [Django]-Django set field value after a form is initialized
- [Django]-Gunicorn Environment Variable Setting