Django перевіряє, чи існує пов’язаний об’єкт, помилка: RelatedObjectDoesNotExist


78

У has_related_objectмоїй моделі є метод, який потрібно перевірити, чи існує пов’язаний об’єкт

class Business(base):
      name =  models.CharField(max_length=100, blank=True, null=True)

  def has_related_object(self):
        return (self.customers is not None) and (self.car is not None)


class Customer(base):
      name =  models.CharField(max_length=100, blank=True, null=True)
      person = models.OneToOneField('Business', related_name="customer")

Але я отримую помилку:

Business.has_related_object ()

RelatedObjectDoesNotExist: Бізнес не має замовника.


1
Я не можу повірити, що Django не забезпечує цей метод.
etlds

Відповіді:


76

Це тому, що ORM повинен перейти до бази даних, щоб перевірити, чи customerіснує. Оскільки він не існує, він створює виняток.

Вам доведеться змінити метод на такий:

def has_related_object(self):
    has_customer = False
    try:
        has_customer = (self.customers is not None)
    except Customer.DoesNotExist:
        pass
    return has_customer and (self.car is not None)

Я не знаю ситуацію з, self.carтому я залишу вас, щоб ви це налаштували, якщо це потрібно.

Примітка: Якщо ви робили це на пристрої, Modelякий має ForeignKeyFieldабо OneToOneFieldна ньому, ви могли б зробити наступне як ярлик, щоб уникнути запиту до бази даних.

def has_business(self):
    return self.business_id is not None

1
Зверніть увагу, що відповідно до документа ( docs.djangoproject.com/en/1.9/ref/models/fields/… ), "[...] ваш код ніколи не повинен мати справу з іменем стовпця бази даних, якщо ви не пишете власний SQL Ви завжди будете мати справу з іменами полів вашого об'єкта моделі. "
Антуан Пінсар

Цей підхід швидший за іншу відповідь, оскільки не вимагає спілкування з базою даних.
Ден,

4
@AntoinePinsard, використання імені стовпця в цьому випадку швидше, оскільки Django не намагатиметься об’єднатись у базовому запиті. Django заохочує ці практики для необхідних оптимізацій. docs.djangoproject.com/en/2.1/topics/db/optimization/…
Bobort

1
Чому Django просто не повертається, Noneякщо ви намагаєтесь запитати об’єкт щодо одного з його зв’язків? Викидання винятку здається надмірним.
mecampbellsoup

2
Ймовірно, це зроблено, щоб охопити випадок наявності поля, що допускає обнулення. Коли дозволено мати значення null, він повертає None. Коли це не так, тоді виникає виняток.
schillingt

154

Використовуйте, hasattr(self, 'customers')щоб уникнути перевірки винятків, як рекомендується в документах Django :

def has_related_object(self):
    return hasattr(self, 'customers') and self.car is not None

4
Взагалі кажучи на python це EAFP. docs.python.org/3/glossary.html#term-eafp
Дастін Вайатт

5
За винятком того, що запитувати дозвіл у цьому випадку однаково просто, і включати все, що намагається: крок речей, як правило, маскує непов’язані помилки, ускладнюючи налагодження проблем.
kloddant
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.