Hi,

I noticed something strange with filtering related objects. Below is a 
complete sample demonstrating the problem. This is only for demonstrating 
the problem.
Django version is 1.9.1

Given the model in a "testapp" app:

############################
from django.db import models

class Blog(models.Model):
    title = models.CharField(max_length=100)
    # subscribers - related from Person
    # subscriptions - related from Subscription
    
    def __str__(self):
        return self.title

class Person(models.Model):
    name = models.CharField(max_length=100)
    subscribed_blogs = models.ManyToManyField(Blog, 
related_name="subscribers", through="Subscription")
    # subscriptions - related from Subscription
    
    def __str__(self):
        return self.name

class Subscription(models.Model):
    person = models.ForeignKey(Person, related_name="subscriptions")
    blog = models.ForeignKey(Blog, related_name="subscriptions")
    subscribed_date = models.DateField()
    
    def __str__(self):
        return ''.join([self.person.name, " - ", self.blog.title])
############################


When I filter "subscribers" of a Blog instance, the results are not 
consistent.
Here is the code demonstrating the effect:


############################
from testapp.models import *
from datetime import datetime

adam = Person.objects.create(name="Adam")
blog_1 = Blog.objects.create(title="Blog 1")
blog_2 = Blog.objects.create(title="Blog 2")
Subscription.objects.create(person=adam, blog=blog_1, 
subscribed_date=datetime(2016,1,10))
Subscription.objects.create(person=adam, blog=blog_2, 
subscribed_date=datetime(2016,1,20))

queryparams = {"subscriptions__subscribed_date__gt": datetime(2016,1,15)}

q1 = blog_1.subscribers.filter(**queryparams)
q2 = blog_1.subscribers.all().filter(**queryparams)
q3 = blog_1.subscribers.get_queryset().filter(**queryparams)
print(q1.query)
print(q1)
print(q2.query)
print(q2)
print(q3.query)
print(q3)

print("--------------------------")

q1 = blog_1.subscribers.filter().filter(**queryparams)
q2 = blog_1.subscribers.all().all().filter(**queryparams)
q3 = blog_1.subscribers.get_queryset().all().filter(**queryparams)
print(q1.query)
print(q1)
print(q2.query)
print(q2)
print(q3.query)
print(q3)
############################


The output is:


SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" 
INNER JOIN "testapp_subscription" ON ("testapp_person"."id" = 
"testapp_subscription"."person_id") WHERE ("testapp_subscription"."blog_id" 
= 1 AND "testapp_subscription"."subscribed_date" > 2016-01-15)
[]
SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" 
INNER JOIN "testapp_subscription" ON ("testapp_person"."id" = 
"testapp_subscription"."person_id") WHERE ("testapp_subscription"."blog_id" 
= 1 AND "testapp_subscription"."subscribed_date" > 2016-01-15)
[]
SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" 
INNER JOIN "testapp_subscription" ON ("testapp_person"."id" = 
"testapp_subscription"."person_id") WHERE ("testapp_subscription"."blog_id" 
= 1 AND "testapp_subscription"."subscribed_date" > 2016-01-15)
[]
--------------------------
SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" 
INNER JOIN "testapp_subscription" ON ("testapp_person"."id" = 
"testapp_subscription"."person_id") INNER JOIN "testapp_subscription" T4 ON 
("testapp_person"."id" = T4."person_id") WHERE 
("testapp_subscription"."blog_id" = 1 AND T4."subscribed_date" > 2016-01-15)
[<Person: Adam>]
SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" 
INNER JOIN "testapp_subscription" ON ("testapp_person"."id" = 
"testapp_subscription"."person_id") INNER JOIN "testapp_subscription" T4 ON 
("testapp_person"."id" = T4."person_id") WHERE 
("testapp_subscription"."blog_id" = 1 AND T4."subscribed_date" > 2016-01-15)
[<Person: Adam>]
SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" 
INNER JOIN "testapp_subscription" ON ("testapp_person"."id" = 
"testapp_subscription"."person_id") INNER JOIN "testapp_subscription" T4 ON 
("testapp_person"."id" = T4."person_id") WHERE 
("testapp_subscription"."blog_id" = 1 AND T4."subscribed_date" > 2016-01-15)
[<Person: Adam>]


The first set of queries simply "AND" the filter params with the 
"subscribers" RelatedManager's inherent related-filtering, while the second 
set of queries do a separate chain filtering.
This is exactly the kind of situation that is described in the django docs 
(with the blogs, "Lennon" and "2008"):
https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

I believe the second set of queries should be the correct one, and that 
should be happening also in the first set of queries, but that is not what 
is happening.

Am I missing something or does this seem like a bug?

Greets,
Balázs


-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/9f913231-2968-4c2f-b415-973f3f521858%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to