Определите заказ для ManyToManyField с django - PullRequest
30 голосов
/ 07 марта 2012

Есть ли способ определить порядок содержимого элементов списка?

пример:

  • ArticleContainer1 содержит в следующем порядке:
    статья1, статья2, статья3, статья6

  • ArticleContainer2 содержит в следующем порядке:
    статья3, статья2, статья1, статья4

  • ArticleContainer3 содержит в следующем порядке:
    article5

Вот мои занятия:

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

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

Ответы [ 4 ]

25 голосов
/ 07 марта 2012

Итак, у меня есть пример, сайт, который организует людей в отделы с заказами по отделам.Это та же концепция, что и ваша проблема, но с разными моделями.В этом примере используется сквозная таблица «многие ко многим».

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)
13 голосов
/ 07 марта 2012

См. Документы от до .

8 голосов
/ 07 марта 2012

Если вы используете явно определенную модель through для отношения m2m, вы можете добавить свой собственный атрибут order-id.Затем вы можете расширить ManyToManyField для заполнения идентификатора заказа согласно вашей логике при создании / обновлении и менеджера m2m модели, который будет сортировать результаты, когда вы выбираете их по атрибуту идентификатора заказа.

1 голос
/ 25 мая 2019

В Django 2.0 принятый принятый ответ Фрэнсиса Яконьелло работает хорошо, за исключением предупреждения, вызванного аргументом max_length для поля order класса DepartmentPeople.

Django игнорирует max_length для целочисленных полей и предупредит вас в Django 1.8 +.

Я бы добавил запись unique_together в подкласс Meta. Meta: #... unique_together = ['person', 'department', 'order'] чтобы предотвратить ошибки ввода данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...