2017-10-18 1 views
0

Ich muss zwei Querysets aus verschiedenen Modellen zu einem kombinieren. Die meisten vorgeschlagenen Lösungen die ich gefunden habe sind online:Wie kombinieren Sie zwei Querysets zu einem aus verschiedenen Modellen?

| zu verwenden und &, aber das funktioniert nur in querysets aus dem gleichen Modell

chain und list zu verwenden, aber das dauert einige der queryset Methoden entfernt und aufgrund der Art, wie der Code in meinem Projekt strukturiert ist, kann ich das nicht ändern. Ich habe es versucht und nicht funktioniert.

Ich lese über Q, aber es ist mir nicht klar, wie ich es anwenden kann, um zu erreichen, was ich brauche.

Grundsätzlich muss ich zwei Abfragegruppen aus verschiedenen Modellen in einem dritten Abfrage-Set, nicht in einer Liste kombinieren. Sie teilen einige Feldnamen, vielleicht ist das nützlich mit Q. Im Beispiel:

queryset_1 = Cars.objects.all().filter(color='red') 
queryset_2 = Horses.objects.all() 

queryset_3 = queryset_1 + queryset_2 

queryset_3.order_by('date') 
+0

Sie können dies nicht tun. Ein queryset definition ist ein Satz von Objekten aus einem einzelnen Modell. –

Antwort

1

Sie können es nicht in der Datenbank oder queryset Ebene leider, weil diese beiden Dinge nicht existieren in der gleichen Datenbanktabelle. Sie können es auf der Python-Seite tun (obwohl es langsamer und rechenintensiver ist).

Unter der Annahme, dass beide Autos und Pferde ein „Datum“ -Attribut haben, können Sie dies tun:

cars = Cars.objects.all().filter(color='red') 
horses = Horses.objects.all() 
all_things = list(cars) + list(horses) 
sorted_things = sorted(all_things, key=lambda x: x.date) 

Eine weitere Option (die auf der Datenbankebene ineffizient ist) wäre sie alles erben von der gleichen zu machen nicht abstraktes Modell.

class Item(models.Model): 
    date = models.DateTimeFiedl() 
    item_type = models.CharField(max_length=255) 

    def get_instance(self): 
     if self.item_type = 'car': 
      return Car.objects.get(id=self.id) 
     elif self.item_type == 'horse': 
      return Horse.objects.get(id=self.id) 

class Car(Item): 
    color = models.CharField(max_length=12) 

    def save(self, *args, **kwargs): 
     self.item_type = 'car' 
     super(Car, self).save(*args, **kwargs) 

class Horse(Item): 
    breed = models.CharField(max_length=25) 

    def save(self, *args, **kwargs): 
     self.item_type = 'horse' 
     super(Horse, self).save(*args, **kwargs) 

Damit können Sie

items = Item.objects.all().order_by('date') 
for item in items: 
    print(type(item)) # Always "Item" 
    actual_item = item.get_instance() 
    if type(actual_item) == Car: 
     print("I am a car") 
    else: 
     print("I am a horse") 

tun, während sie durchlaufen jedes spezifische Element greifen je nach Bedarf (ähnlich wie Bachstelze Griffe Seiten, machen Sie eine bequeme Methode zum Greifen eines Objekts auf der Grundlage ihrer Übergeordnete Klasse)

2

Wenn Sie wirklich solche Abfrage benötigen, könnte dies ein Symptom sein, dass die Modelle falsch entworfen sind, mit dem Risiko, dass eine schnelle Lösung wahrscheinlich mühsamer zu warten wäre, als Ihre Modelle zu überarbeiten. Mein Vorschlag ist, ein einzelnes Modell zu erstellen, das sowohl Auto als auch Pferd ersetzt (auch wenn einige Felder für die Fälle in jedem Fall leer bleiben), mit einem separaten Feld, damit Sie die beiden leicht identifizieren können. Zum Beispiel:

class Vehicle(models.Model): 
    category = models.IntegerField(
     choices=[(10, 'Horse'), (20, 'Car'), (30, 'Bicycle')] 
    ) 
    # other fields here... 
+0

Was meinst du, ich denke, heißt Datenbank-Normalisierung: https://en.wikipedia.org/wiki/Database_normalization – White

+0

Richtig! Das ist es genau. – davecaputo

+0

Meine Lösung war eine Mischung aus dem Ansatz, den Sie vorschlagen, und der Verwendung der Liste. Aber Ihr Kommentar stimmt, das Projekt entwickelte sich in Bezug auf die Code-Organisation auf eine merkwürdige Weise. –

Verwandte Themen