2016-06-06 9 views
2

Ich habe zwei Modelle:Django- Duplikate nur entfernen, wenn ein Feld vorhanden ist

class BookSeries(models.Model): 
    title = models.CharField(max_length=200, null=False, blank=False, unique=True) 
    #extra fields 

class Book(models.Model): 
    series = models.ForeignKey(BookSeries, blank=True, null=True, default=None) 
    publisher = models.ForeignKey(Publisher, default=None, null=True, blank=True) 
    title = models.CharField(max_length=200, null=False, blank=False, unique=True) 
    #extra fields 

Jetzt möchte ich alle Bücher abzufragen, die zu einer Serie gehört nicht und nur einer von jeder des Buches, das gehören zu derselben Serie (Serie kann null sein).

Problemstellung:

ich wan alle einzelnen Bücher und Serien abzufragen. Da eine Serie mehrere Bücher haben kann, und ein Buch darf nicht zu einer Serie gehören. Eine der Lösungen besteht darin, alle Buchobjekte abzufragen (die nicht zu einer Reihe gehören) und alle Serienobjekte wie beschrieben here abzufragen. Aber das würde alle Serien zusammen und Bücher zusammen in der Antwort geben. Ich möchte nicht, dass sie zusammen gruppiert werden (ich verwende auch Paginierung).

so etwas wie: Book.objects.filter(disctinct only if(series is not None))

Ich dachte an verschiedenen und ausschließen verwenden, aber konnte es nicht funktioniert.

+0

Welche Datenbank benutzen Sie? – AKS

+0

@AKS postgresql – dnit13

Antwort

1

würde ich folgende Vorgehensweise vorschlagen:

  1. Erhalten id aller Bücher, die zu einem series gehören nicht:

    ids_list1 = list(Book.objects.filter(series=None).values_list('id', flat=True)) 
    
  2. id aller Bücher erhalten, die zu einem Zwischen nur series und erhalten zuerst mit distinct:

    ids_list2 = list(Book.objects 
            .exclude(series=None) # exclude ones which are not in a series 
            .order_by('series')  # order by series 
            .distinct('series')  # keep the first book in each series 
            .values_list('id', flat=True)) 
    

Jetzt können Sie diese beiden Listen kombinieren und eine weitere Abfrage mit diesen IDs nur die Bücher zurück machen:

ids = id_list1 + id_list2 
books = Book.objects.filter(id__in=ids) 
0

Erste ausschließen wenn über Serie None ist, dann rufen Sie distinct() kehren Sie eine Liste.

Book.objects.exclude(series=None).distinct('series')

Wenn Sie die bevorzugte Art und Weise Nullwerte und leere Strings ausschließen müssen, so zu tun ist, um Kette zusammen die Bedingungen wie folgt: Book.objects.exclude(series__isnull=True).exclude(series__exact='')

Sie können diesen Thread zum besseren Verständnis folgen Filtering for empty or NULL names in a queryset

+0

Dies würde nur Bücher zur Verfügung stellen, die nicht Teil der Serie sind, ich möchte auch ein Buch aus einer Reihe. wie von AKS vorgeschlagen – dnit13