2016-04-15 8 views
0

ich einige Prototypen mache und haben ein einfaches Modell wie dieseserstellen Modell für MySQL Ansicht und kommen auf sie

class SampleModel(models.Model): 
    user_id = models.IntegerField(default=0, db_index=True) 
    staff_id = models.IntegerField(default=0, db_index=True) 
    timestamp = models.DateTimeField(default=timezone.now, db_index=True) 

    objects = AsOfManager() 

Jetzt brauchen wir Anfragen zu tun, die eine selbst erfordern beitreten, die in rohen SQL geschrieben sind so etwas wie dies einfach:

SELECT X.* FROM no_chain_samplemodel as X 
    JOIN (SELECT user_id, MAX(timestamp) AS timestamp 
     FROM no_chain_samplemodel 
     GROUP BY user_id) AS Y 
    ON (X.user_id = Y.user_id and X.timestamp = Y.timestamp); 

diese Abfrage für jede zurückgeben sollte user_id was ist die letzte Zeile Bestellung durch Zeitstempel. Jede dieser "Ketten" (von user_id-bezogenen Zeilen) könnte potenziell Tausende von Zeilen enthalten.

Jetzt könnte ich rohe SQL verwenden, aber dann verliere ich die Komposibilität, ich möchte ein anderes Abfrage-Set zurückgeben. Und gleichzeitig wäre es schön, auch das Schreiben von Raw SQL einfacher zu machen, also dachte ich, ich könnte eine Datenbankansicht verwenden.

könnte die Ansicht dieser nur so etwas wie

CREATE VIEW no_chain_sample_model_with_max_date AS SELECT user_id AS id, MAX(timestamp) AS timestamp 
         FROM no_chain_samplemodel 
         GROUP BY user_id; 

werden, so das Modell, das so einfach zu der Ansicht, bezieht sich sein könnte:

class SampleModelWithMaxDate(models.Model): 
    class Meta: 
     managed = False 
     db_table = 'no_chain_sample_model_with_max_date' 

    id = models.IntegerField(default=0, primary_key=True) 
    timestamp = models.DateTimeField(default=timezone.now, db_index=True) 

gibt es jedoch ein paar Probleme:

  1. auch wenn verwaltet = False './manage.py makemigrations' erstellt immer noch die Migration für diese Tabelle. Ich habe sogar versucht, die Migration dort zu lassen, aber das Modell mit Raw SQL zu ersetzen, um die Ansicht aber kein Glück zu erstellen.

  2. Ich muss jetzt select_related tun, um die beiden Tabellen zu verbinden und abzufragen, aber wie soll ich das tun?

    habe ich versucht, einen Fremdschlüssel auf SampleModel wie folgt aus:

    by_date = models.ForeignKey (SampleModelWithMaxDate, null = True)

    aber das funktioniert auch nicht:

    OperationalError: (1054 "Unknown column 'no_chain_sample_model_with_max_date.by_date_id' in 'field list'")

So im allgemeinen mir nicht einmal sicher bin, ob es möglich ist, kann ich se Die anderen Leute, die Modelle mit Ansichten benutzen und nur das unabhängige Modell abfragen, das auch für mich funktioniert, aber ist es möglich, etwas schlauer zu machen?

Dank

+0

Aus Ihrer Frage immer noch nicht klar ist, was Sie brauchen? Könntest du ein Beispiel geben, wenn das Django-Modell ganz oben steht? – AKS

+0

Nun, ich muss nur diese SQL-Abfrage mit dem Django ORM übersetzen. Also da Beitritt auf der gleichen Tabelle scheint im Grunde unmöglich, ohne dass ein Fremdschlüssel auf sich selbst zeigt, dachte ich, dass eine Sicht und ein anderes Modell das Problem lösen würde. Aber ich habe nicht wirklich irgendein Beispiel von jemanden gesehen, der ein DB-Modell verwendet, das auf einer DB-Ansicht basiert, wie ich es gerne würde, also frage ich mich, ob das überhaupt möglich ist. –

+0

Das ist in Ordnung, aber was ist das Endergebnis, das Sie erwarten. Möchten Sie alle Instanzen von 'SampleModel' für jede' user_id' mit dem letzten 'timestamp' abrufen? – AKS

Antwort

1

ich nicht ORM-Methode erhalten finden konnten, was Sie in einer Abfrage wollen, aber wir konnten Art, dies zu tun mit zwei Abfragen:

Zuerst wir max timestamp für alle Nutzer erhalten

latest_timestamps = SampleModel.objects.values('user_id') 
         .annotate(max_ts=Max('timestamp')).values('max_ts') 

Hier values(user_id) arbeitet als group by Betrieb.

Jetzt erhalten wir alle instanecs von SampleModel mit den genauen Zeitstempel

qs = SampleModel.objects.filter(timestamp__in=latest_timestamps)  

PostgreSQL speficic beantworten:

Sie könnten order_by mischen und distinct zu erreichen, was Sie wollen:

SampleModel.objects.order_by('user_id', '-timestamp').distinct('user_id') 

Brechen it down:

# order by user_id, and in decreasing order of timestamp 
qs = SampleModel.objects.order_by('user_id', '-timestamp') 

# get distinct rows using user_id, this will make sure that the first entry for 
# each user is retained and since we further ordered in decreasing order of 
# timestamp for each user the first entry will have last row added 
# for the user in the database. 
qs = qs.distinct('user_id') 
+0

Ich glaube, ich versuchte, dass aber MySQL unterstützen „DISTINCT ON“ nicht so dass ich nicht wirklich zu tun verwalten .. NotImplementedError: DISTINCT ON Felder wird von dieser Datenbank-Backend unterstützt In [11]: In [11]: models.SampleModel.objects.order_by ('user_id', '-zeitstempel'). Distinct ('user_id'). Count() –

+0

oh ja, 'distinct' funktioniert nur in postgres. Lass mich sehen, ob ich etwas für mysql finden kann. – AKS

+0

@andrea_rotti Ich habe versucht, deine Frage zu beantworten, ohne 'distinct' zu verwenden. Bitte überprüfen Sie die aktualisierte Antwort. – AKS

Verwandte Themen