2013-06-16 34 views
11

Sanırım Django'nun filter() yönteminin nasıl çalıştığı konusunda çok temel ve temel bir şey eksik.Django filter() ilgili modelin alanında

kullanarak, aşağıdaki modeller:

len(Collection.objects.filter(item__flag=True)) 
:
class Collection(models.Model): 
    pass 

class Item(models.Model): 
    flag = models.BooleanField() 
    collection = models.ForeignKey(Collection) 

ve söz altındaki doldurmak() işlev çağırarak sağlanan veriler

, ./manage.py kabuğu aşağıdaki yürütme deneyin

Beklentim, bunun "2" yi basmasıydı; bu, en az bir Öğeyi bayrak = True olan Öğelerin sayısıdır. Bu beklenti, "Bu örnek, adı" Beatles Blog "olan bir Blog'la tüm Giriş nesnelerini alır" şeklindeki bir örneğe sahip olan https://docs.djangoproject.com/en/1.5/topics/db/queries/#lookups-that-span-relationships belgesindeki belgelere dayanıyordu. Ancak, yukarıdaki çağrı aslında "6" basıyor; bu, flag = True olan Item kayıtlarının sayısıdır. Geri dönen gerçek nesneler ise Koleksiyon nesneleridir. Aynı Collection nesnesini bayrak = True ile her bir karşılık gelen Öğe kaydı için bir kez daha döndürüyor gibi görünüyor. Bu, True (Doğru) yazdırılan

tarafından onaylanabilir.

Bu doğru davranış mı? Eğer öyleyse mantık nedir? Beklendiği takdirde, belgeler kesinlikle doğru olarak yorumlanabilir, ancak her nesnenin birden çok kez gönderilebileceğini söylemekten kaçınır.

Burada çok şaşırtıcı (veya sadece yanlış yanlış) davranışlar gibi görünen bir örnek var. Bu bir durumda beni yakaladı nerede bir dışlama() çağrısı bir özel model yöneticisi tarafından eklenen ediliyordu ve arayan sonra bir filtre() ekleyerek oldu:

from django.db.models import Count  
[coll.count for coll in Collection.objects.filter(item__flag=True).annotate(count=Count("item"))] 
[coll.count for coll in Collection.objects.exclude(item=None).filter(item__flag=True).annotate(count=Count("item"))] 

ilk vaka baskılar "[2,4]" ama ikinci baskılar "[8,16]" !!!

Doldur fonksiyonu:

def populate(): 
    Collection.objects.all().delete() 

    collection = Collection() 
    collection.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 

    collection = Collection() 
    collection.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 

    collection = Collection() 
    collection.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 

cevap

12

Bu iki bölümü vardır çıkıyor. Birincisi, belgenin belirttiği farklı() yöntemidir:

Varsayılan olarak, bir QuerySet yinelenen satırları ortadan kaldırmaz. Pratikte, , bu nadiren bir sorundur çünkü Blog.objects.all() gibi basit sorgular, satırlarının yinelenen sonucu olasılığını tanımaz. Ancak, sorgunuzda birden fazla tablo varsa, bir QuerySet değerlendirildiğinde yinelenen sonuç elde edebilirsiniz. Diğer bir deyişle, , farklı() kullanın. beklenen "2" olarak

aşağıdaki çıkışlar:

len(Collection.objects.filter(item__flag=True).distinct()) 

Ancak bu annotate kullanılarak, I verdi Daha karmaşık bir örnek ile yardım etmez(). Bu, bilinen bir sorunun bir örneğidir: https://code.djangoproject.com/ticket/10060.

İlgili konular