2016-04-04 15 views
0

Ich möchte in der Lage sein zu überprüfen, ob ein verwandtes Objekt bereits mit select_related oder prefetch_related abgerufen wurde, so dass ich die Daten entsprechend serialisieren kann. Hier ein Beispiel:Gibt es eine Möglichkeit zu überprüfen, ob ein verwandtes Objekt bereits abgerufen wurde?

class Address(models.Model): 
    street = models.CharField(max_length=100) 
    zip = models.CharField(max_length=10) 

class Person(models.Model): 
    name = models.CharField(max_length=20) 
    address = models.ForeignKey(Address) 

def serialize_address(address): 
    return { 
     "id": address.id, 
     "street": address.street, 
     "zip": address.zip 
    } 

def serialize_person(person): 
    result = { 
     "id": person.id, 
     "name": person.name 
    } 
    if is_fetched(person.address): 
     result["address"] = serialize_address(person.address) 
    else: 
     result["address"] = None 

###### 

person_a = Person.objects.select_related("address").get(id=1) 
person_b = Person.objects.get(id=2) 

serialize_person(person_a) #should be object with id, name and address 
serialize_person(person_b) #should be object with only id and name 

In diesem Beispiel wird die Funktion is_fetched ist das, was ich suche. Ich möchte feststellen, ob das Personenobjekt bereits eine Adresse aufgelöst hat und nur wenn es vorhanden ist, sollte es auch serialisiert werden. Wenn dies nicht der Fall ist, sollte keine weitere Datenbankabfrage ausgeführt werden.

Gibt es einen Weg, dies in Django zu erreichen?

Antwort

3

Wenn die address-Beziehung abgerufen wurde, dann wird das Person-Objekt ein gefülltes Attribut namens _address_cache haben; Sie können dies überprüfen.

def is_fetched(obj, relation_name): 
    cache_name = '_{}_cache'.format(relation_name) 
    return getattr(obj, cache_name, False) 

Hinweis müssen Sie diese mit dem Objekt nennen und der Namen der Beziehung:

is_fetched(person, 'address') 

seit person.address tun würde die sofort holen auslösen.

Bearbeiten Umgekehrte oder Viele-zu-viele-Beziehungen können nur durch prefetch_related abgerufen werden; Das füllt ein einzelnes Attribut _prefetched_objects_cache, das ein Diktat von Listen ist, in denen der Schlüssel der Name des verwandten Modells ist. Wenn Sie zB tun:

addresses = Address.objects.prefetch_related('person_set') 

dann jedes Element in addresses einen "person' Schlüssel enthält eine _prefetched_objects_cache dict haben.

Beachten Sie, dass beide Attribute Single-Underscore sind, was bedeutet, dass sie Teil der privaten API sind; Du kannst sie nutzen, aber Django kann sie auch in zukünftigen Versionen ändern.

+0

Danke, das klingt vielversprechend. Funktioniert es auch für ManyToMany-Beziehungen oder Reverse ForeignKey-Beziehungen? Zum Beispiel: '_topping_set_cache'? – basilikum