36๐
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)
- [Django]-How to render .rst files in a markdown or html format?
- [Django]-Django ModelForm: What is save(commit=False) used for?
- [Django]-Why does my Django admin site not have styles / CSS loading?
11๐
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.
- [Django]-How to set another Inline title in Django Admin?
- [Django]-Phpmyadmin logs out after 1440 secs
- [Django]-Get objects from a many to many field
6๐
On Django 2.0, the accepted answer of Francis Yaconiello works well with the exception of a warning caused by the max_length argument for the order
field of class DepartmentPeople
.
Django ignores max_length for integer fields, and will warn you in Django 1.8+.
I would add a unique_together entry in the Meta subclass
class Meta:
#...
unique_together = ['person', 'department', 'order']
to prevent data entry errors.
- [Django]-Render HTML to PDF in Django site
- [Django]-Django form โ set label
- [Django]-Sending post data from angularjs to django as JSON and not as raw content
1๐
I use that plugin: https://github.com/jazzband/django-sortedm2m
This works just fine
I had some troubles with migrations because i hadnโt read usage of the plugin, pay attention on it
- [Django]-Django ModelForm override widget
- [Django]-Class Based Views VS Function Based Views
- [Django]-Sqlite3.OperationalError: unable to open database file
1๐
An alternative: if you just have a few items in the ManyToManyField, and you prefer not to introduce too much complexity, you could opt to add a priority
to the ManyToManyField
and define ordering
in Meta:
class Article(models.Model):
title = models.CharField(max_length=200)
priority = models.PositiveSmallIntegerField(default=16383)
class ArticleContainer(models.Model):
contents = models.ManyToManyField(Article, blank=True, null=True)
class Meta:
ordering = ['priority', 'name']
A PositiveSmallIntegerField
ranges from 0 to 32767. The closer to zero, the higher the field will appear.
- [Django]-Django rest framework nested self-referential objects
- [Django]-Form field description in django admin
- [Django]-Cross domain at axios