Was tun, wenn Djangos ORM zu einfach ist?
Verfasst: Samstag 25. Oktober 2008, 20:27
Ich baue mir gerade etwas wie Ubuntu Brainstorm. Dort können Anwender Vorschläge machen, bewerten und kommentieren. Nun möchte ich Listen von Vorschlägen basierend auf der Aktivität der Anwender berechnen.
Mein Django-Modell sieht so aus:
Um die Vorschläge nach der Höhe der Stimmwerte zu sortieren, schummle ich und speichere in `Proposal` diesen Wert, den ich nach jeder Änderung in `Vote` aktualisiere. Das SQL dazu sieht so aus, was ich mit Djangos ORM dank `extra()` gerade eben noch hinbekomme.
Die Liste aller Vorschläge, sortiert nach dem Stimmwert, ohne diesen Wert zu speichern, sähe wohl so aus:
Will ich die Vorschläge finden, bei denen in den letzten 7 Tagen die meiste Aktivität war, muss ich `sum` in `count` ändern und noch ein `and v.created_at >= ?` einfügen, wobei `?` für einen Zeitpunkt vor 7 Tagen steht, oder? Habe ich irgendeine Chance, das auch in Django auszudrücken?
Wie finde ich alle Vorschläge, die zuletzt kommentiert wurden? Was wären sonst noch sinnvolle Abfragen, damit nicht immer nur die beliebtesten Vorschläge zu sehen sind, die dadurch noch beliebter werden?
Bitte keine Vorschläge, wie ich das mit SQLalchemy o.ä. ermitteln kann, denn das kann und will ich aus Django nicht so ohne weiteres einsetzen.
Hat jemand stattdessen schon mal damit experimentiert, SQL-artige Ausdrücke wie den da oben automatisch in backend-spezfisches SQL umzuschreiben? Ich möchte eigentlich nicht Tabellennamen und Spaltennamen hart verdrahten, sondern immer über die Django-Modelle gehen.
Ich wäre bereit zu garantieren, die Zeilenumbrüche immer so zu machen, sodass es auch mit regulären Ausdrücken recht einfach sein sollte, `from` und ähnliches zu finden. Etwas in geschweiften Klammern (oder meinetwegen auch Backquotes) wäre dann entweder der Klassenname eines Modells oder ein Attributname, wobei man dann alle beteiligten Modelle durchsucht oder eine Punkt-Notation benutzen muss. Gibt es schon so was in fertig oder muss man da selbst ran?
Ist überhaupt klar, was ich meine? ;)
Stefan
Mein Django-Modell sieht so aus:
Code: Alles auswählen
class Proposal(models.Model):
author = models.ForeignKey(User, related_name='proposals')
created_at = models.DateTimeField(editable=False)
description = models.TextField()
...
def vote_up(self, user): self._vote(user, +1)
def vote_down(self, user): self._vote(user, -1)
def _vote(self, user, value):
vote, created = self.votes.get_or_create(voter=user, defaults={...})
if not created:
vote.value = value
vote.created_at = datetime.datetime.now
vote.save()
class Vote(models.Model):
voter = models.ForeignKey(User, related_name='votes')
proposal = models.ForeignKey(Proposal, related_name='votes')
created_at = models.DateTimeField(editable=False)
value = models.IntegerField(choices=(-1, +1))
...
Code: Alles auswählen
select sum(value) from ..._vote where proposal_id = ?
Code: Alles auswählen
select p.*, sum(value) as s
from {Proposal} p, {Vote} v
where v.proposal_id = p.id
group by v.proposal_id
order by s
Wie finde ich alle Vorschläge, die zuletzt kommentiert wurden? Was wären sonst noch sinnvolle Abfragen, damit nicht immer nur die beliebtesten Vorschläge zu sehen sind, die dadurch noch beliebter werden?
Bitte keine Vorschläge, wie ich das mit SQLalchemy o.ä. ermitteln kann, denn das kann und will ich aus Django nicht so ohne weiteres einsetzen.
Hat jemand stattdessen schon mal damit experimentiert, SQL-artige Ausdrücke wie den da oben automatisch in backend-spezfisches SQL umzuschreiben? Ich möchte eigentlich nicht Tabellennamen und Spaltennamen hart verdrahten, sondern immer über die Django-Modelle gehen.
Ich wäre bereit zu garantieren, die Zeilenumbrüche immer so zu machen, sodass es auch mit regulären Ausdrücken recht einfach sein sollte, `from` und ähnliches zu finden. Etwas in geschweiften Klammern (oder meinetwegen auch Backquotes) wäre dann entweder der Klassenname eines Modells oder ein Attributname, wobei man dann alle beteiligten Modelle durchsucht oder eine Punkt-Notation benutzen muss. Gibt es schon so was in fertig oder muss man da selbst ran?
Ist überhaupt klar, was ich meine? ;)
Stefan