使用django定义ManyToManyField的订单

时间:2012-03-07 13:15:17

标签: python django

我有办法定义内容列表项的顺序吗?

例如:

  • ArticleContainer1按此顺序包含:
       第1条,第2条,第3条,第6条

  • ArticleContainer2按此顺序包含:
     第3条,第2条,第1条,第4条

  • ArticleContainer3按此顺序包含:
     第五条

以下是我的课程:

class Article(models.Model):    
    title = models.CharField(max_length=200)

class ArticleContainer(models.Model):
   contents = models.ManyToManyField(Article, blank=True, null=True)

6 个答案:

答案 0 :(得分:22)

所以这是我的一个例子,一个将人们组织成按部门排序的部门的网站。它与您的问题具有相同的概念,但具有不同的模型。此示例使用多对多表格。

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        

通过模型:

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)

管理员:

class DepartmentPeopleInline(admin.TabularInline):
    model = DepartmentPeople
    extra = 1

class DepartmentAdmin(admin.ModelAdmin):
    inlines = (DepartmentPeopleInline,)

admin.site.register(Person, PersonAdmin)
admin.site.register(Department, DepartmentAdmin)

征求意见:

注意:以下是我的PersonAdmin,但是对于这个例子来说它是不必要的复杂。你可以用一个简单的

class PersonAdmin(admin.ModelAdmin) :
    pass

但这就是我在我的应用中使用的内容:

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)

答案 1 :(得分:12)

请参阅有关through的文档。

答案 2 :(得分:8)

如果您为m2m关系使用明确定义的through模型,则可以添加自己的属性order-id。然后,您可以扩展ManyToManyField以根据您在创建/更新时的逻辑填充order-id和模型m2m管理器,该管理器将在您通过order-id属性获取结果时对结果进行排序。

答案 3 :(得分:1)

我使用该插件:https://github.com/jazzband/django-sortedm2m
这样就可以了
我在迁移时遇到了一些麻烦,因为我没有阅读插件的用法,请注意

答案 4 :(得分:0)

在Django 2.0上,accepted answer of Francis Yaconiello可以很好地工作,但由order类的DepartmentPeople字段的max_length参数引起的警告除外。

Django会忽略整数字段的max_length,并会在Django 1.8+中警告您。

我将通过添加以下内容使该字段唯一 unique=True 以防止数据输入错误。

答案 5 :(得分:0)

另一种选择:如果您在 ManyToManyField 中只有几个项目,并且您不想引入太多复杂性,您可以选择向 priority 添加一个 ManyToManyField 并定义 {{1 }}在元:

ordering

A 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'] 的范围从 0 到 32767。越接近于零,字段显示的越高。