7

tat meinem erstes echtes Django-Projekt führt und Unterstützung benötigen.Beschriften SUM Aggregationsfunktion auf ‚Keinen‘ Wert in Django

Hintergrund: Mein Projekt ist ein Reddit-Klon. Benutzer senden Links + Text. Besucher Upvote oder Downvote. Es gibt einen Social_Ranking-Algo, der alle 2 Minuten als Hintergrundskript läuft, alle Einsendungen nach Nettostimmen und Frische des Inhalts wiederholt. Ziemlich Vanille Zeug.

Problem: Bestellung von votes nicht richtig funktioniert, weil votes als None statt 0 initialisiert werden. Dies führt dazu, dass Einreichungen mit None Stimmen unterhalb von Einreichungen mit negativen Stimmen liegen. Ich habe dieses Problem seit Tagen ausgetestet - kein Glück.

Besonderheiten: Ich habe mein Modell Modell-Manager über geschüttelten eine Sum Aggregationsfunktion auf die Abfrage Satz mit Anmerkungen zu versehen, und dann, um die genannten Abfrage gesetzt von ‚sozialem Rang‘ und Stimmen.

Unten ist mein models.py. Ich verwende Django 1.5, so einige Sachen, die man hier sehen kann, nicht auf 1,8 entsprechen (zB get_query_set vs get_queryset):

class LinkVoteCountManager(models.Manager): 
    def get_query_set(self): 
     return super(LinkVoteCountManager, self).get_query_set().annotate(votes=Sum('vote__value')).order_by('-rank_score', '-votes') 

class Link(models.Model): 
    description = models.TextField(_("Write something")) 
    submitter = models.ForeignKey(User) 
    submitted_on = models.DateTimeField(auto_now_add=True) 
    rank_score = models.FloatField(default=0.0) 
    url = models.URLField(_("Link"), max_length=250, blank=True) 

    with_votes = LinkVoteCountManager() 
    objects = models.Manager() 

    def __unicode__(self): 
     return self.description 

    def set_rank(self): 
     # Based on reddit ranking algo at http://amix.dk/blog/post/19588 
     epoch = datetime(1970, 1, 1).replace(tzinfo=None) 
     netvotes = self.votes # 'NONE' votes are messing up netvotes amount. 
     if netvotes == None: 
      netvotes = 0 
     order = log(max(abs(netvotes), 1), 10) 
     sign = 1 if netvotes > 0 else -1 if netvotes < 0 else 0 
     unaware_submission = self.submitted_on.replace(tzinfo=None) 
     td = unaware_submission - epoch 
     epoch_submission = td.days * 86400 + td.seconds + (float(td.microseconds)/1000000) 
     secs = epoch_submission - 1432201843 
     self.rank_score = round(sign * order + secs/45000, 8) 
     self.save() 

class Vote(models.Model): 
    voter = models.ForeignKey(User) 
    link = models.ForeignKey(Link) 
    value = models.IntegerField(null=True, blank=True, default=0) 

    def __unicode__(self): 
     return "%s gave %s to %s" % (self.voter.username, self.value, self.link.description) 

Bei Bedarf sind die folgenden relevanten Abschnitte von meinem views.py:

class LinkListView(ListView): 
    model = Link 
    queryset = Link.with_votes.all() 
    paginate_by = 10 

    def get_context_data(self, **kwargs): 
     context = super(LinkListView, self).get_context_data(**kwargs) 
     if self.request.user.is_authenticated(): 
      voted = Vote.objects.filter(voter=self.request.user) 
      links_in_page = [link.id for link in context["object_list"]] 
      voted = voted.filter(link_id__in=links_in_page) 
      voted = voted.values_list('link_id', flat=True) 
      context["voted"] = voted 
     return context 

class LinkCreateView(CreateView): 
    model = Link 
    form_class = LinkForm 

    def form_valid(self, form): 
     f = form.save(commit=False) 
     f.rank_score=0 
     f.with_votes = 0 
     f.category = '1' 
     f.save() 
     return super(CreateView, self).form_valid(form) 

Kann jemand beleuchten, was ich brauche das „None“ Problem zu beheben, zu tun? Danke im Voraus.

+0

Was ist, wenn Sie null = False setzen, wobei default = 0 ist? –

Antwort

11

Drücken Sie einfach die gleiche Wand, obwohl ich None Einträge sie über die Ergebnisse aus ignorieren wählte durch Ausschluss. Ich nehme an, du willst das nicht.

BTW, diese Frage das gleiche Problem hat Annotating a Sum results in None rather than zero

Was die andere Lösung als die Verwendung einer benutzerdefinierten SQL wie in dieser Frage die Antwort darauf hingewiesen, können Sie Django verwenden 1.8 statt und gehen für die Lösung in der darauf hingewiesen, (!) Ticket offen in Djangos Bug-tracker für mehr als 6 Jahre https://code.djangoproject.com/ticket/10929

Coalesce(Sum('field'), 0) 

So Ihr Manager wäre:

class LinkVoteCountManager(models.Manager): 
    def get_query_set(self): 
     return super(LinkVoteCountManager, self).get_query_set().annotate(
      votes=Coalesce(Sum('vote__value'), 0) 
     ).order_by(
      '-rank_score', 
      '-votes' 
     ) 

PS: Ich habe den Code nicht getestet, da ich selbst Django 1.8 nicht verwende.

+0

Danke für diesen Mann! –

+0

@HassanBaig Ich bin froh, dass ich helfen konnte – alfetopito

1

Sie könnten auch die Linie

netvotes = self.votes

zu

netvotes = self.votes or 0

ersetzen und Sie können jetzt die if-Anweisung entfernen.

Wie in vielen anderen Sprachen wird der Wert falsy (None, 0, "") oder der letzte Wert "0" in diesem speziellen Fall zurückgegeben.