django - مرشح جانغو() في مجال نموذج ذات الصلة



django-models django-queryset (1)

أعتقد أنني في عداد المفقودين شيء أساسي جدا وأساسي حول كيفية مرشح مرشح جانغو () من المفترض أن تعمل.

استخدام النماذج التالية:

class Collection(models.Model): 
    pass

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

ومع البيانات المقدمة من خلال استدعاء الدالة () في الجزء السفلي من السؤال، حاول تنفيذ ما يلي في ./manage.py شل:

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

كان توقعي هو أن هذا سيطبع "2"، وهو عدد المجموعات التي تحتوي على عنصر واحد على الأقل مع العلم = صحيح. استند هذا التوقع على الوثائق في https://docs.djangoproject.com/en/1.5/topics/db/queries/#lookups-that-span-relationships ، الذي يحتوي على مثال يقول "هذا المثال يسترد جميع الكائنات دخول مع مدونة باسمها "مدونة البيتلز".

ومع ذلك، المكالمة أعلاه يطبع فعلا "6"، وهو عدد سجلات البند التي لديها علم = صحيح. الكائنات الفعلية التي تم إرجاعها هي كائنات جمع، على الرغم من. يبدو أنها تعيد نفس كائن المجموعة عدة مرات، مرة واحدة لكل سجل عنصر المقابلة مع العلم = صحيح. ويمكن تأكيد ذلك من خلال:

queryset = Collection.objects.filter(item__flag=True)
queryset[0] == queryset[1]

الذي يطبع صحيح.

هل هذا هو السلوك الصحيح؟ إذا كان الأمر كذلك فما هو الأساس المنطقي؟ إذا كان هو ما هو متوقع، يمكن تفسير الوثائق على أنها صحيحة تماما، لكنه يغفل القول بأن كل كائن يمكن إرجاع عدة مرات.

هنا هو مثال ذات الصلة، والذي يبدو أنه من المستغرب جدا (أو مجرد خطأ خاطئ) السلوك. انها اشتعلتني في حالة حيث يتم إضافة استدعاء () دعوة من قبل مدير نموذج مخصص وكان المتصل ثم إضافة عامل تصفية ():

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"))]

الحالة الأولى تطبع "[2،4]"، ولكن المطبوعات الثانية "[8،16]" !!!

ملء وظيفة:

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()

اتضح أن هناك جزأين لهذا. الأول هو الأسلوب المميز () الذي يقول المستند:

بشكل افتراضي، لن يقوم كريسيت بإزالة الصفوف المكررة. في الممارسة العملية، هذا نادرا ما يكون مشكلة، لأن الاستعلامات البسيطة مثل Blog.objects.all () لا يعرض إمكانية الصفوف نتيجة مكررة. ومع ذلك، إذا كان الاستعلام الخاص بك يمتد جداول متعددة، فمن الممكن الحصول على نتائج مكررة عند تقييم كيريسيت. هذا عندما كنت تستخدم متميزة ().

النواتج التالية "2" كما هو متوقع:

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

ومع ذلك، هذا لا يساعد مع المثال الأكثر تعقيدا أعطيت، وذلك باستخدام التعليق التوضيحي (). اتضح أن هذا هو مثال من مشكلة معروفة: https://code.djangoproject.com/ticket/10060 .





django-queryset