93

私はこのような2つのモデルを持っています:

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


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

ユーザーがType1またはType2プロファイルを持っている場合は、何かをする必要があります。

if request.user.type1profile != None:
    # do something
elif request.user.type2profile != None:
    # do something else
else:
    # do something else

ただし、type1またはtype2プロファイルを持たないユーザーの場合、そのようなコードを実行すると、次のエラーが発生します。

Type1Profile matching query does not exist.

ユーザーが持っているプロファイルのタイプを確認するにはどうすればよいですか?

ありがとう

4

8 に答える 8

102

(OneToOne)リレーションが存在するかどうかを確認するには、次のhasattr関数を使用できます。

if hasattr(request.user, 'type1profile'):
    # do something
elif hasattr(request.user, 'type2profile'):
    # do something else
else:
    # do something else
于 2012-01-26T09:50:22.957 に答える
22

とてもシンプルなので、ジョクティーの答えが好きです。

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

他のコメント投稿者は、Python または Django の特定のバージョンでは機能しない可能性があるという懸念を提起しましたが、Django のドキュメントでは、この手法がオプションの 1 つとして示されています。

hasattr を使用して、例外をキャッチする必要を回避することもできます。

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

もちろん、ドキュメントには例外をキャッチするテクニックも示されています。

p2 には関連付けられたレストランがありません:

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

例外をキャッチすると何が起こっているのかが明確になるというJoshuaの意見に同意しますが、私には面倒に思えます。おそらくこれは合理的な妥協でしょうか?

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

Restaurantこれは、場所ごとにオブジェクトをクエリしているだけです。Noneその場所にレストランがない場合に返されます。

オプションを操作するための実行可能なスニペットを次に示します。Python、Django、および SQLite3 がインストールされている場合は、実行する必要があります。Python 3.8.10 と Django 4.0.2 でテストしました。

""" Django models in a single, runnable file.

Based on Nsukami's blog post: https://nskm.xyz/posts/dsfp/

To get it running, copy it into a directory named udjango:
$ pip install django
$ python udjango_models.py

Tested with Django 4.0 and Python 3.8.
"""
import logging
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'
DB_FILE = NAME + '.db'


def main():
    setup()

    class Place(models.Model):
        name = models.CharField(max_length=50)
        address = models.CharField(max_length=80)

        def __str__(self):
            return "%s the place" % self.name

    class Restaurant(models.Model):
        place = models.OneToOneField(Place, on_delete=models.CASCADE, primary_key=True)
        serves_hot_dogs = models.BooleanField(default=False)
        serves_pizza = models.BooleanField(default=False)

        def __str__(self):
            return "%s the restaurant" % self.place.name

    class Waiter(models.Model):
        restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
        name = models.CharField(max_length=50)

        def __str__(self):
            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():
    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()
于 2015-09-23T18:31:40.110 に答える
10

try/except ブロックを使用するのはどうですか?

def get_profile_or_none(user, profile_cls):

    try:
        profile = getattr(user, profile_cls.__name__.lower())
    except profile_cls.DoesNotExist:
        profile = None

    return profile

じゃあこんな使い方!

u = request.user
if get_profile_or_none(u, Type1Profile) is not None:
    # do something
elif get_profile_or_none(u, Type2Profile) is not None:
    # do something else
else:
    # d'oh!

元のクラス (ここではプロファイル クラス) と関連するインスタンス (ここでは request.user) を指定して、逆の OneToOne インスタンスを取得するための汎用関数としてこれを使用できると思います。

于 2011-02-04T18:44:10.653 に答える
3

使用してくださいselect_related

>>> user = User.objects.select_related('type1profile').get(pk=111)
>>> user.type1profile
None
于 2013-02-07T04:37:54.260 に答える
0

私は has_attr の組み合わせを使用しており、None です:

class DriverLocation(models.Model):
    driver = models.OneToOneField(Driver, related_name='location', on_delete=models.CASCADE)

class Driver(models.Model):
    pass

    @property
    def has_location(self):
        return not hasattr(self, "location") or self.location is None
于 2019-07-14T12:35:16.420 に答える