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)
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.
@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.
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)
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With