2016-06-24 11 views
1

einige Code wie folgt gegeben:Django ausschließen auf mehrere Felder in Unterabfrage

# coding: utf-8 
import datetime 

from django.db import models 
from django.contrib.auth.models import User 
from django.contrib.sites.models import Site 


class Premium(models.Model): 
    """Access to Premium Features™®.""" 
    end = models.DateField() 
    user = models.ForeignKey(User) 
    site = models.ForeignKey(Site) 


def get_ending_premiums(): 
    """Get a queryset of all Premiums for which a user has none following.""" 
    tomorrow = datetime.date.today() + datetime.timedelta(days=1) 
    future_premiums = Premium.objects.filter(end__gt=tomorrow).values('user', 'site') 
    return Premium.objects.filter(end=tomorrow).exclude(

     # Would love if something like this actually worked... 
     user_and_site__in=future_premiums, 
    ) 

Wie kann ich get_ending_premiums() vervollständigen? Eines der wichtigsten Dinge ist, dass ich Premium nur dann möchte, wenn es keinen anderen gibt, der später endet, , aber pro Site. Also, wenn ein Benutzer einen anderen Premium auf Lebensmittelgeschäfte.com hat, wird derjenige, der morgen endet, nicht zurückgegeben, aber wenn sie keinen weiteren Premium auf offersupplies.com haben, wird dieser zurückgegeben.

(Beachten Sie die Zeile mit den Bemerkungen, bevor es nicht wirklich funktioniert ... das ist der Teil I ausfüllen müssen.)

kann ich herausfinden, wie diese außerhalb des ORM zu tun, aber ich würde wirklich eine ORM-Lösung vorziehen, da wir in ein paar Monaten den Datenbank-Anbieter wechseln wollen, also versuche ich, so viel Roh-SQL wie möglich zu vermeiden.

Hier ist ein Test für das Verhalten, das ich erhalten möchte:

class PremiumTest(TestCase): 

    def test_gets_ending_premiums(self): 
     today = date(2020, 6, 5) 
     tomorrow = today + timedelta(days=1) 
     next_year = today + timedelta(days=366) 
     groceries = Site.objects.create(domain='groceries.com') 
     catvids = Site.objects.create(domain='catvids.com') 
     dave = User.objects.create_user('dave') 
     sally = User.objects.create_user('sally') 
     Premium.objects.create(user=dave, site=groceries, end=tomorrow) 
     Premium.objects.create(user=dave, site=groceries, end=next_year) 
     Premium.objects.create(user=dave, site=catvids, end=tomorrow) 
     Premium.objects.create(user=sally, site=groceries, end=tomorrow) 
     Premium.objects.create(user=sally, site=catvids, end=tomorrow) 
     Premium.objects.create(user=sally, site=catvids, end=next_year) 

     ending_premiums = get_ending_premiums(today) 
     ending = set((p.user, p.site) for p in ending_premiums) 

     self.assertNotIn((dave, groceries), ending) 
     self.assertIn((dave, catvids), ending) 
     self.assertIn((sally, groceries), ending) 
     self.assertNotIn((sally, catvids), ending) 
     self.assertEqual(2, len(ending_premiums)) 

Antwort

0

Ich habe mit diesem kommen ... Es hat etwas roh SQL, aber es gibt immer noch eine QuerySet mit normalen QuerySet Methoden (obwohl es die scheinbar veraltete QuerySet.extra()-Methode) verwendet fragt

def get_ending_premiums(day=None): 
    """Get a queryset of Premiums for which a user has none following.""" 
    if day is None: 
     day = date.today() 
    tomorrow = day + timedelta(days=1) 

    ending_premiums = Premium.objects.filter(
     end=tomorrow, 
    ).extra(
     where=['NOT EXISTS (SELECT NULL FROM premium_premium child where premium_premium.site_id = site_id AND premium_premium.user_id = user_id AND end > %s)'], 
     params=[tomorrow], 
    ) 
    return ending_premiums 

Dennoch, wenn es nicht ein besserer Weg ...

Verwandte Themen