Check if OneToOneField is None in Django

后端 未结 8 1782
走了就别回头了
走了就别回头了 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:31

    I like joctee's answer, because it's so simple.

    if hasattr(request.user, 'type1profile'):
        # do something
    elif hasattr(request.user, 'type2profile'):
        # do something else
    else:
        # do something else
    

    Other commenters have raised concerns that it may not work with certain versions of Python or Django, but the Django documentation shows this technique as one of the options:

    You can also use hasattr to avoid the need for exception catching:

    >>> hasattr(p2, 'restaurant')
    False
    

    Of course, the documentation also shows the exception catching technique:

    p2 doesn’t have an associated restaurant:

    >>> from django.core.exceptions import ObjectDoesNotExist
    >>> try:
    >>>     p2.restaurant
    >>> except ObjectDoesNotExist:
    >>>     print("There is no restaurant here.")
    There is no restaurant here.
    

    I agree with Joshua that catching the exception makes it clearer what's happening, but it just seems messier to me. Perhaps this is a reasonable compromise?

    >>> print(Restaurant.objects.filter(place=p2).first())
    None
    

    This is just querying the Restaurant objects by place. It returns None if that place has no restaurant.

    Here's an executable snippet for you to play with the options. If you have Python, Django, and SQLite3 installed, it should just run. I tested it with Python 2.7, Python 3.4, Django 1.9.2, and SQLite3 3.8.2.

    # Tested with Django 1.9.2
    import sys
    
    import django
    from django.apps import apps
    from django.apps.config import AppConfig
    from django.conf import settings
    from django.core.exceptions import ObjectDoesNotExist
    from django.db import connections, models, DEFAULT_DB_ALIAS
    from django.db.models.base import ModelBase
    
    NAME = 'udjango'
    
    
    def main():
        setup()
    
        class Place(models.Model):
            name = models.CharField(max_length=50)
            address = models.CharField(max_length=80)
    
            def __str__(self):              # __unicode__ on Python 2
                return "%s the place" % self.name
    
        class Restaurant(models.Model):
            place = models.OneToOneField(Place, primary_key=True)
            serves_hot_dogs = models.BooleanField(default=False)
            serves_pizza = models.BooleanField(default=False)
    
            def __str__(self):              # __unicode__ on Python 2
                return "%s the restaurant" % self.place.name
    
        class Waiter(models.Model):
            restaurant = models.ForeignKey(Restaurant)
            name = models.CharField(max_length=50)
    
            def __str__(self):              # __unicode__ on Python 2
                return "%s the waiter at %s" % (self.name, self.restaurant)
    
        syncdb(Place)
        syncdb(Restaurant)
        syncdb(Waiter)
    
        p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
        p1.save()
        p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
        p2.save()
        r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
        r.save()
    
        print(r.place)
        print(p1.restaurant)
    
        # Option 1: try/except
        try:
            print(p2.restaurant)
        except ObjectDoesNotExist:
            print("There is no restaurant here.")
    
        # Option 2: getattr and hasattr
        print(getattr(p2, 'restaurant', 'There is no restaurant attribute.'))
        if hasattr(p2, 'restaurant'):
            print('Restaurant found by hasattr().')
        else:
            print('Restaurant not found by hasattr().')
    
        # Option 3: a query
        print(Restaurant.objects.filter(place=p2).first())
    
    
    def setup():
        DB_FILE = NAME + '.db'
        with open(DB_FILE, 'w'):
            pass  # wipe the database
        settings.configure(
            DEBUG=True,
            DATABASES={
                DEFAULT_DB_ALIAS: {
                    'ENGINE': 'django.db.backends.sqlite3',
                    'NAME': DB_FILE}},
            LOGGING={'version': 1,
                     'disable_existing_loggers': False,
                     'formatters': {
                        'debug': {
                            'format': '%(asctime)s[%(levelname)s]'
                                      '%(name)s.%(funcName)s(): %(message)s',
                            'datefmt': '%Y-%m-%d %H:%M:%S'}},
                     'handlers': {
                        'console': {
                            'level': 'DEBUG',
                            'class': 'logging.StreamHandler',
                            'formatter': 'debug'}},
                     'root': {
                        'handlers': ['console'],
                        'level': 'WARN'},
                     'loggers': {
                        "django.db": {"level": "WARN"}}})
        app_config = AppConfig(NAME, sys.modules['__main__'])
        apps.populate([app_config])
        django.setup()
        original_new_func = ModelBase.__new__
    
        @staticmethod
        def patched_new(cls, name, bases, attrs):
            if 'Meta' not in attrs:
                class Meta:
                    app_label = NAME
                attrs['Meta'] = Meta
            return original_new_func(cls, name, bases, attrs)
        ModelBase.__new__ = patched_new
    
    
    def syncdb(model):
        """ Standard syncdb expects models to be in reliable locations.
    
        Based on https://github.com/django/django/blob/1.9.3
        /django/core/management/commands/migrate.py#L285
        """
        connection = connections[DEFAULT_DB_ALIAS]
        with connection.schema_editor() as editor:
            editor.create_model(model)
    
    main()
    

提交回复
热议问题