#7872: Some complex lookups with Q objects (or-style) don't return all matching
model objects.
-------------------------------------+--------------------------------------
 Reporter:  [EMAIL PROTECTED]  |       Owner:  nobody    
   Status:  new                      |   Milestone:            
Component:  Database wrapper         |     Version:  SVN       
 Keywords:                           |       Stage:  Unreviewed
Has_patch:  0                        |  
-------------------------------------+--------------------------------------
 When using Q objects to make some complex queries, the resulting queryset
 does not contain all expected objects. Here is an example case:

 Models:
 {{{
 class ExtendedUser(User):
         """
         This class inherits (MTI-style) from auth.models.User to add extra
 fields, and is the parent class
         for the SupportStaff and Client classes to keep things DRY.
         """
         parent = models.OneToOneField(User, parent_link=True)
         middle_initial = models.CharField(max_length=10, blank=True)
         title = models.CharField(max_length=50, blank=True)
         office_building = models.ForeignKey("Building", null=True,
 blank=True)
         office_number = models.CharField(max_length=15, blank=True)
         phone = models.PhoneNumberField(blank=True)
         twitter = models.CharField(max_length=50, blank=True)
         pownce = models.CharField(max_length=50, blank=True)
         aim = models.CharField(max_length=50, blank=True)
         msn = models.CharField(max_length=50, blank=True)
         yahoo = models.CharField(max_length=50, blank=True)

         def get_full_name(self):
                 if self.middle_initial:
                         return u"%s %s %s" % (self.first_name,
 self.middle_initial, self.last_name)
                 else:
                         return super(ExtendedUser, self).get_full_name()

         def __unicode__(self):
                 return u"%s" % self.get_full_name()

         class Meta:
                 ordering = ('last_name', 'first_name')
                 verbose_name = u'Extended User'
                 verbose_name_plural = u'Extended Users'

 class SupportStaff(ExtendedUser):
         """
         This class inherits from the model class ExtendedUser (itself a
 subclass of auth User model).
         This should only be used for people who are going to provide end-
 user support services.
         """
         parent = models.OneToOneField(ExtendedUser, parent_link=True)
         coverage = models.ManyToManyField("OrgUnit",
 related_name="support_staff_coverage", null=True, blank=True)
         expertise = models.ManyToManyField("SpecialSkill",
 related_name="support_staff_expertise", null=True, blank=True)

         def __unicode__(self):
                 return u"%s" % self.get_full_name()

 class SupportTicket(models.Model):
         call_source = models.ForeignKey("CallSource", null=True,
 blank=True)
         client = models.ManyToManyField(Client)
         call_description = models.TextField("Call Description",
 max_length=500)
         call_type = models.ManyToManyField("CallType")
         equipment_tag = models.CharField(max_length=50, null=True,
 blank=True)
         priority = models.CharField(choices=PRIORITY_LEVELS, default=3,
 max_length=2)
         target_date = models.DateTimeField("Target Date and Time",
 null=True, blank=True)
         call_status = models.ForeignKey("CallStatus")
         cause = models.ManyToManyField("Cause", null=True, blank=True)
         solution = models.TextField(max_length=500, blank=True)
         date_created = models.DateTimeField(default=datetime.datetime.now,
 editable=False)
         created_by = models.ForeignKey(SupportStaff,
 related_name='ticket_created')
         date_modified = models.DateTimeField(null=True, blank=True,
 editable=False)
         last_modified_by = models.ForeignKey(SupportStaff,
 related_name='ticket_modified_by', null=True, blank=True)
         date_closed = models.DateTimeField(null=True, blank=True)
         closed_by = models.ForeignKey(User,
 related_name='ticket_closed_by', null=True, blank=True)

 class Assignment(models.Model):
         support_ticket = models.ForeignKey(SupportTicket,
 edit_inline=models.STACKED, num_in_admin=1,
 related_name='assignment_made')
         group_assigned = models.ForeignKey(Group, core=True)
         group_notified = models.NullBooleanField(editable=False)
         support_staff_assigned = models.ForeignKey(SupportStaff,
 related_name='staff_assignment', null=True, blank=True)
         support_staff_notified = models.NullBooleanField(editable=False)
         notes = models.TextField(max_length=500, blank=True)
         acknowledge = models.BooleanField(default=False)
         date_created = models.DateTimeField(default=datetime.datetime.now,
 editable=False)
         created_by = models.ForeignKey(SupportStaff,
 related_name='assigned_by')
         date_modified =
 models.DateTimeField(default=datetime.datetime.now, editable=False)
         last_modified_by = models.ForeignKey(SupportStaff,
 related_name='assignment_modified_by', null=True, blank=True)
         date_acknowledged = models.DateTimeField(null=True, blank=True,
 editable=False)
 }}}

 Queries:

 {{{

 >>> t4 =
 SupportTicket.objects.filter(assignment_made__group_assigned__user=u)
 >>> t5 = SupportTicket.objects.filter(created_by__parent__parent=u)
 >>> t6 =
 
SupportTicket.objects.filter(Q(assignment_made__group_assigned__user=u)|Q(created_by__parent__parent=u)).distinct()
 >>> t4
 [<SupportTicket: 3>, <SupportTicket: 2>, <SupportTicket: 1>]
 >>> t5
 [<SupportTicket: 5>, <SupportTicket: 3>, <SupportTicket: 2>,
 <SupportTicket: 1>]
 >>> t6
 [<SupportTicket: 3>, <SupportTicket: 2>, <SupportTicket: 1>]
 >>>
 
str(SupportTicket.objects.filter(Q(assignment_made__group_assigned__user=u)|Q(created_by__parent__parent=u)).distinct().query)
 'SELECT DISTINCT "tickets_supportticket"."id",
 "tickets_supportticket"."call_source_id",
 "tickets_supportticket"."call_description",
 "tickets_supportticket"."equipment_tag",
 "tickets_supportticket"."priority", "tickets_supportticket"."target_date",
 "tickets_supportticket"."call_status_id",
 "tickets_supportticket"."solution",
 "tickets_supportticket"."date_created",
 "tickets_supportticket"."created_by_id",
 "tickets_supportticket"."date_modified",
 "tickets_supportticket"."last_modified_by_id",
 "tickets_supportticket"."date_closed",
 "tickets_supportticket"."closed_by_id" FROM "tickets_supportticket" LEFT
 OUTER JOIN "tickets_assignment" ON ("tickets_supportticket"."id" =
 "tickets_assignment"."support_ticket_id") INNER JOIN "auth_group" ON
 ("tickets_assignment"."group_assigned_id" = "auth_group"."id") LEFT OUTER
 JOIN "auth_user_groups" ON ("auth_group"."id" =
 "auth_user_groups"."group_id") WHERE ("auth_user_groups"."user_id" = 6  OR
 "tickets_supportticket"."created_by_id" = 6 ) ORDER BY
 "tickets_supportticket"."date_created" DESC'

 }}}

-- 
Ticket URL: <http://code.djangoproject.com/ticket/7872>
Django Code <http://code.djangoproject.com/>
The web framework for perfectionists with deadlines
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to