Code

Opened 5 years ago

Closed 5 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: UI/UX:

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

Attachments (0)

Change History (4)

comment:1 Changed 5 years ago by kmtracey

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to worksforme
  • Status changed from new to closed

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 Changed 5 years ago by pbzrpa

  • Resolution worksforme deleted
  • Status changed from closed to reopened

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 Changed 5 years ago by pbzrpa

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 Changed 5 years ago by pbzrpa

  • Resolution set to worksforme
  • Status changed from reopened to closed

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.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.