Check if OneToOneField is None in Django

后端 未结 8 1640
走了就别回头了
走了就别回头了 2021-01-30 10:04

I have two models like this:

class Type1Profile(models.Model):
    user = models.OneToOneField(User, unique=True)
    ...


class Type2Profile(models.Model):
            


        
相关标签:
8条回答
  • 2021-01-30 10:46

    It's possible to see if a nullable one-to-one relationship is null for a particular model simply by testing the corresponding field on the model for Noneness, but only if you test on the model where the one-to-one relationship originates. For example, given these two classes…

    class Place(models.Model):
        name = models.CharField(max_length=50)
        address = models.CharField(max_length=80)
    
    class Restaurant(models.Model):  # The class where the one-to-one originates
        place = models.OneToOneField(Place, blank=True, null=True)
        serves_hot_dogs = models.BooleanField()
        serves_pizza = models.BooleanField()
    

    … to see if a Restaurant has a Place, we can use the following code:

    >>> r = Restaurant(serves_hot_dogs=True, serves_pizza=False)
    >>> r.save()
    >>> if r.place is None:
    >>>    print "Restaurant has no place!"
    Restaurant has no place!
    

    To see if a Place has a Restaurant, it's important to understand that referencing the restaurant property on an instance of Place raises a Restaurant.DoesNotExist exception if there is no corresponding restaurant. This happens because Django performs a lookup internally using QuerySet.get(). For example:

    >>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
    >>> p2.save()
    >>> p2.restaurant
    Traceback (most recent call last):
        ...
    DoesNotExist: Restaurant matching query does not exist.
    

    In this scenario, Occam's razor prevails, and the best approach for making a determination about whether or not a Place has a Restautrant would be a standard try / except construct as described here.

    >>> try:
    >>>     restaurant = p2.restaurant
    >>> except Restaurant.DoesNotExist:
    >>>     print "Place has no restaurant!"
    >>> else:
    >>>     # Do something with p2's restaurant here.
    

    While joctee's suggestion to use hasattr works in practice, it really only works by accident since hasattr suppresses all exceptions (including DoesNotExist) as opposed to just AttributeErrors, like it should. As Pi Delport pointed out, this behavior was actually corrected in Python 3.2 per the following ticket: http://bugs.python.org/issue9666. Furthermore — and at the risk of sounding opinionated — I believe the above try / except construct is more representative of how Django works, while using hasattr can cloud the issue for newbies, which may create FUD and spread bad habits.

    EDIT Don Kirkby's reasonable compromise also seems reasonable to me.

    0 讨论(0)
  • 2021-01-30 10:50

    Use select_related!

    >>> user = User.objects.select_related('type1profile').get(pk=111)
    >>> user.type1profile
    None
    
    0 讨论(0)
提交回复
热议问题