Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define an order for ManyToManyField with Django

Tags:

python

django

Is there a way to define the order of objects related through a ManyToManyField?

Example:

  • ArticleContainer1 contains in this order :
    article1, article2, article3, article6

  • ArticleContainer2 contains in this order :
    article3, article2, article1, article4

  • ArticleContainer3 contains in this order :
    article5

Here are my classes :

class Article(models.Model):         title = models.CharField(max_length=200)  class ArticleContainer(models.Model):    contents = models.ManyToManyField(Article, blank=True, null=True) 
like image 953
Christophe Debove Avatar asked Mar 07 '12 13:03

Christophe Debove


People also ask

How do you order many-to-many fields in Django?

If you use a explicitly defined through model for m2m relationship you can add your own attribute order-id . Then You can extend ManyToManyField to populate order-id per your logic on create/update and a model m2m manager that will sort the results when you fetch them by the order-id attribute.

What is Auto_created in Django?

@Raphael In a migration, an auto_created model gets created by the AddField operation for the ManyToManyField -- it does not exist as a separate model, only as part of the model that defines the m2m field.


1 Answers

So this is an example I have, a site that organizes people into departments with per department ordering. Its the same concept as your problem but with different models. This example uses many-to-many through table.

class Department(models.Model):     slug = models.SlugField(         verbose_name    = _(u'Slug'),         help_text           = _(u'Uri identifier for this department.'),         max_length=255     )     name = models.CharField(         verbose_name    = _(u'Department Name'),         help_text           = _(u'The department\'s name.'),         max_length      = 255     )     description = models.TextField(         verbose_name    = _(u'Description'),         help_text           = _(u'Department\'s description')     )     people = models.ManyToManyField(         Person,         through             = 'DepartmentPeople',         related_name    = 'people',         verbose_name    = _(u'People'),         help_text           = _(u'People in this Department')     )     order_by = models.IntegerField(         verbose_name    = _(u'Ordering Weight'),          help_text           = _(u'This item\'s weight within a list.'),         max_length      = 255     )      class Meta:         verbose_name = _(u"Department")         verbose_name_plural = _(u"Departments")         ordering = ['order_by',]      def people_list(self):         return [dp.person for dp in DepartmentPeople.objects.filter(department=self).order_by('order')]      def __unicode__(self):         return self.name         

And the through model:

class DepartmentPeople(models.Model):     person = models.ForeignKey(         Person,         verbose_name    = _(u'Person'),         help_text           = _(u'Person is a member of this deparment.'),     )     department = models.ForeignKey(         Department,         verbose_name    = _(u'Department'),         help_text           = _(u'Pseron is a member of this department.'),     )            order = models.IntegerField(         verbose_name    = _(u'Order'),         help_text           = _(u'What order to display this person within the department.'),         max_length      = 255     )      class Meta:         verbose_name = _(u"Department Person")         verbose_name_plural = _(u"Department People")         ordering = ['order',]      def __unicode__(self):         return self.person.first_name + " " + self.person.last_name + " is a member of " + self.department.name + (" in position %d" % self.order) 

And the admin:

class DepartmentPeopleInline(admin.TabularInline):     model = DepartmentPeople     extra = 1  class DepartmentAdmin(admin.ModelAdmin):     inlines = (DepartmentPeopleInline,)  admin.site.register(Person, PersonAdmin) admin.site.register(Department, DepartmentAdmin) 

REQUEST IN COMMENT:

Note: the following is my PersonAdmin, but its needlessly complicated for this example. you could get by with a simple

class PersonAdmin(admin.ModelAdmin) :     pass 

BUT this is what i'm using in my app:

class PersonForm(forms.ModelForm):     abstract = forms.CharField(         widget=TinyMCE(attrs={'cols': 80, 'rows': 30})     )      class Meta:         model = Person  class PersonAdmin(reversion.VersionAdmin):     form = PersonForm     # The Form Fieldsets     fieldsets = [         (             None,             {                 'fields'    : [('first_name', 'last_name', 'post_nominal', ), 'slug', 'title', 'headshot', 'large_photo', ('email', 'phone', ), 'abstract']             },         )     ]      # Prepopulated fields     prepopulated_fields = {'slug': ('first_name', 'last_name', 'post_nominal', )}      # Fields that are readonly     #readonly_fields = ('slug', )      def formfield_for_dbfield(self, db_field, **kwargs):         if db_field.name == 'headshot':             request = kwargs.pop("request", None)             kwargs['widget'] = AdminImageWidget             return db_field.formfield(**kwargs)         return super(PersonAdmin, self).formfield_for_dbfield(db_field, **kwargs) 
like image 160
Francis Yaconiello Avatar answered Nov 07 '22 04:11

Francis Yaconiello