Django prüft, ob ein verwandtes Objekt vorhanden ist Fehler: RelatedObjectDoesNotExist

77

Ich habe eine Methode has_related_objectin meinem Modell, die überprüfen muss, ob ein verwandtes Objekt vorhanden ist

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")

Aber ich bekomme den Fehler:

Business.has_related_object ()

RelatedObjectDoesNotExist: Unternehmen hat keinen Kunden.

Prometheus
quelle
1
Ich kann nicht glauben, dass Django diese Methode nicht anbietet.
etlds

Antworten:

75

Dies liegt daran, dass der ORM in die Datenbank gehen muss, um zu überprüfen, ob er customervorhanden ist. Da es nicht existiert, wird eine Ausnahme ausgelöst.

Sie müssen Ihre Methode wie folgt ändern:

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)

Ich kenne die Situation nicht, self.caralso überlasse ich es Ihnen, sie anzupassen, wenn es nötig ist.

Randnotiz: Wenn Sie dies auf einem Modelmit ForeignKeyFieldoder OneToOneFieldtun würden, könnten Sie Folgendes als Verknüpfung ausführen, um die Datenbankabfrage zu vermeiden.

def has_business(self):
    return self.business_id is not None
schillingt
quelle
1
Beachten Sie, dass laut Dokument ( docs.djangoproject.com/de/1.9/ref/models/fields/… ) "[...] Ihr Code niemals mit dem Namen der Datenbankspalte umgehen muss, es sei denn, Sie schreiben benutzerdefiniertes SQL Sie werden sich immer mit den Feldnamen Ihres Modellobjekts befassen. "
Antoine Pinsard
Dieser Ansatz ist schneller als die andere Antwort, da keine Kommunikation mit der Datenbank erforderlich ist.
Dan
4
@AntoinePinsard, in diesem Fall ist die Verwendung des Spaltennamens schneller, da Django nicht versucht, einen Join in der zugrunde liegenden Abfrage durchzuführen. Django empfiehlt diese Praktiken für notwendige Optimierungen. docs.djangoproject.com/de/2.1/topics/db/optimization/…
Bobort
1
Warum kehrt Django nicht einfach zurück, Nonewenn Sie versuchen, ein Objekt nach einer seiner Beziehungen abzufragen? Eine Ausnahme auszulösen scheint übertrieben.
Mecampbellsoup
2
Es wird wahrscheinlich getan, um den Fall eines nullbaren Feldes abzudecken. Wenn es null sein darf, wird None zurückgegeben. Wenn dies nicht der Fall ist, wird eine Ausnahme ausgelöst.
Schillingt
151

Verwenden Sie hasattr(self, 'customers')diese Option , um die in Django-Dokumenten empfohlene Ausnahmeprüfung zu vermeiden :

def has_related_object(self):
    return hasattr(self, 'customers') and self.car is not None
mrts
quelle
4
Im Allgemeinen ist es in Python EAFP. docs.python.org/3/glossary.html#term-eafp
Dustin Wyatt
5
Abgesehen davon, dass es in diesem Fall genauso einfach ist, um Erlaubnis zu bitten und alles in try einzuschließen: Mit Ausnahme von Klauseln werden nicht verwandte Fehler maskiert, was das Debuggen von Problemen erschwert.
Kloddant