Define an order for ManyToManyField with Django

后端 未结 5 591
清酒与你
清酒与你 2020-12-13 02:15

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

Example:

  • ArticleContainer1 contains in this order :
    article

相关标签:
5条回答
  • 2020-12-13 02:30

    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.

    0 讨论(0)
  • 2020-12-13 02:38

    See the docs about through.

    0 讨论(0)
  • 2020-12-13 02:39

    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.

    0 讨论(0)
  • 2020-12-13 02:50

    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)
    
    0 讨论(0)
  • 2020-12-13 02:50

    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

    0 讨论(0)
提交回复
热议问题