在 Django Admin 中将 ManyToManyWidget 添加到 ManyToManyField 的反面

2022-01-25 00:00:00 python django django-models django-admin

问题描述

假设我在 Django 1.4 中有一个简单的博客应用程序:

Let's say I have a simple blog app in Django 1.4:

class Post(models.Model):
    title = …
    published_on = …
    tags = models.ManyToManyField('Tag')

class Tag(models.Model):
    name = …

即一个帖子有很多标签.在 Django 管理员上,如果我在 fields 中为 PostAdmin<包含 tags,我会得到一个不错的小 <select multi>/代码>.有没有一种简单的方法可以在 TagAdmin 中包含帖子列表(作为简单的 <select multi>)?我尝试将 fields = ['name', 'posts'] 放入 TagAdmin 并得到 ImproperlyConfigured 错误.(post_set 的结果相同).

i.e. a post has many tags. On the Django admin, I get a nice little <select multi> if I include tags in the fields for the PostAdmin. Is there an easy way to include the list of the posts (as a simple <select multi>) in the TagAdmin? I tried putting fields = ['name', 'posts'] in the TagAdmin and got an ImproperlyConfigured error. (same result for post_set).

我对 Django 没问题,所以可以创建一个适当的 AdminForm 和 Admin 对象,但我希望有一个 Right Way™ 来做.

I'm alright with Django, so could whip up a proper AdminForm and Admin object, but I'm hoping there a Right Way™ to do it.


解决方案

这可以通过自定义表单来实现.

This is possible to do with a custom form.

from django.contrib import admin
from django import forms

from models import Post, Tag

class PostAdminForm(forms.ModelForm):
    tags = forms.ModelMultipleChoiceField(
        Tag.objects.all(),
        widget=admin.widgets.FilteredSelectMultiple('Tags', False),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super(PostAdminForm, self).__init__(*args, **kwargs)
        if self.instance.pk:
            self.initial['tags'] = self.instance.tags.values_list('pk', flat=True)

    def save(self, *args, **kwargs):
        instance = super(PostAdminForm, self).save(*args, **kwargs)
        if instance.pk:
            instance.tags.clear()
            instance.tags.add(*self.cleaned_data['tags'])
        return instance

class PostAdmin(admin.ModelAdmin):
    form = PostAdminForm

admin.site.register(Post, PostAdmin)

如果您想要垂直堆叠的小部件,可以将其中的 False 替换为 True.

That False in there can be replaced with a True if you want vertically stacked widget.

相关文章