Opened 14 years ago

Closed 14 years ago

#12406 closed (worksforme)

Model Meta ordering bug with manytomany field

Reported by: pbzrpa Owned by: nobody
Component: Uncategorized Version: 1.1
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

There seems to be a problem with ordering in a model meta class when you have a manytomany field in the model. It sorts the queryset grouped by the manytomany field.

Example:

class RelationType(models.Model):
    name = models.CharField(max_length = 30)
    editable = models.BooleanField(default=True)

    def __unicode__(self):
        return u'%s' % self.name

class Relation(models.Model):
    code = models.CharField(max_length = 20, primary_key = True)
    relationtype = models.ManyToManyField(RelationType)
    short_name = models.CharField(max_length = 30)
    full_name = models.CharField(max_length = 100, null = True, blank = True)
    pref_comm = models.ForeignKey(RelationCommunicationType, verbose_name = 'Perferred Comm')

    def __unicode__(self):
        return u'%s' % self.short_name

    class Meta:
        ordering = ('short_name',)

When you do Relation.objects.all() it sorts according to the short name but in lists grouped by the manytomany field.

So you would have a result like:

Short Name   |   Type
ab           |   Sup
abc          |   Sup
bcd          |   Sup
abcd         |   Cust

instead of

Short Name   |   Type
ab           |   Sup
abc          |   Sup
abcd         |   Cust
bcd          |   Sup

Change History (4)

comment:1 by Karen Tracey, 14 years ago

Resolution: worksforme
Status: newclosed

I think you've left something key out of how to recreate this problem. Using the models you show, Relation.objects.all() won't do anything to even retrieve any of the related RelationType instances. The DB query generated is quite simple, orders by short name, and produces the correct results:

>>> from ttt.models import Relation
>>> Relation.objects.all()
[<Relation: ab>, <Relation: abc>, <Relation: abcd>, <Relation: bcd>]
>>> from django.db import connection
>>> connection.queries[-1]
{'time': '0.003', 'sql': u'SELECT "ttt_relation"."code", "ttt_relation"."short_name", "ttt_relation"."full_name" FROM "ttt_relation" ORDER BY "ttt_relation"."short_name" ASC LIMIT 21'}
>>> 

What code did you use to generate the tables show above? That's likely where the problem lies.

comment:2 by pbzrpa, 14 years ago

Resolution: worksforme
Status: closedreopened

Thank you for your response.

In [6]: Relation.objects.all()
Out[6]: [<Relation:  Alcagen>, <Relation:  Amazitech Computers>, <Relation:  Axiz>, <Relation:  Centurion Technology Cc>, <Relation:  Compu Cable Projects>, <Relation:  Eco Technology>,
 <Relation:  Frog>, <Relation:  Game World>, <Relation:  Infosat>, <Relation:  Klj Consulting Cc>, <Relation:  Micro Vision Computers>, <Relation:  Service Parts Logistics>, 
<Relation:  Sound And Lighting>, <Relation:  Tarsus>, <Relation:  Wirecom Pty Ltd>, <Relation: Adele'S Escorts>, <Relation: Aga Air Conditioning>, 
<Relation: Aga Aircon Services>, <Relation: Aga Cape Town>, <Relation: Akhuna Mathata>, '...(remaining elements truncated)...']

In [7]: from django.db import connection

In [8]: connection.queries[-1]
Out[8]:
{'sql': u'SELECT `relations_relation`.`code`, `relations_relation`.`short_name`, `relations_relation`.`full_name`, `relations_relation`.`pref_comm_id` FROM `relations_relation` 
ORDER BY `relations_relation`.`short_name` ASC LIMIT 21', 'time': '0.002'}

Please note that in the queryset the order changes at <Relation: Wirecom Pty Ltd>. The first set of records until <Relation: Wirecom Pty Ltd> have one relationtype manytomany linked to it and the rest have a different manytomany relationtype. Here is another copy of my model.

class RelationType(models.Model):
    name = models.CharField(max_length = 30)
    editable = models.BooleanField(default=True)

    def __unicode__(self):
        return u'%s' % self.name

class Relation(models.Model):
    code = models.CharField(max_length = 20, primary_key = True)
    relationtype = models.ManyToManyField(RelationType)
    short_name = models.CharField(max_length = 30)
    full_name = models.CharField(max_length = 100, null = True, blank = True)
    pref_comm = models.ForeignKey(RelationCommunicationType, verbose_name = 'Perferred Comm')

    def __unicode__(self):
        return u'%s' % self.short_name

    def type_split(self):
        return ",".join( [ x.name for x in self.relationtype.all()] )

    class Meta:
        ordering = ('short_name',)

comment:3 by pbzrpa, 14 years ago

Here is the result of the RelationType queryset.

In [9]: from cc.relations.models import RelationType

In [10]: RelationType.objects.all()
Out[10]: [<RelationType: Customer>, <RelationType: Supplier>, <RelationType: Branch>]

The records up to <Relation: Wirecom Pty Ltd> have a relationtype <RelationType: Supplier>, the rest have <RelationType: Customer>.

Hope that helps.

comment:4 by pbzrpa, 14 years ago

Resolution: worksforme
Status: reopenedclosed

Please forgive me for wasting your time. I found the problem. During my import all the Supplier records got a space in front of the short_name and that is why it was sorting like that. Will remember that in future. Sorry and thank you for your trouble.

Note: See TracTickets for help on using tickets.
Back to Top