在django admin中如何为ManyToManyField的反面添加一个字段

时间:2013-02-20 16:30:10

标签: django django-admin

我有两个模型,'产品'和'范围',由多个到多个字段链接。 'Product'类在我没写的应用程序中,因此无法修改(我可以为它编辑modeladmin)。我希望在管理员中可以编辑“范围”和“产品”,我希望使用FilteredSelectMultiple,而不是内联管理员。

简化的'models.py':

class Product(models.Model):
    name = models.CharField(max_length=64)
    #etc...
    #I can't modify this class

class Range(models.Model):
    name = models.CharField(max_length=32)
    products = models.ManyToManyField(Product, related_name='ranges')

和admin.py:

class ProductAdmin(admin.ModelAdmin):
    # What do I put here to get a multi-select box for ranges?
    # Preferrably with one of those 'add' buttons to popup a window
    # to add ranges.

如果我可以修改产品,我可以使用现有的直通表在其上放置一个ManyToManyField,这样可以正常工作,但正如我所说的那样我不能(或者不会因为它会使外部应用程序的升级真实疼痛)。

提前感谢您的帮助! (PS我希望在这里很容易看到为什么我不想使用内联管理表单 - 这会使UI变得不必要地复杂化。)

1 个答案:

答案 0 :(得分:2)

对不起它可能有点晚了,但谷歌搜索的任何人都可以从这个答案中受益。这不是那么容易,但它是可行的。您必须构建自己的表单(如果需要,可以从现有表单下载),然后手动加载和保存项目。

from django import forms
from django.contrib import admin

class ProductForm(forms.ModelForm):
    # <- your own fields declaration
    ranges = forms.ModelMultipleChoiceField(
        label='Ranges',
        queryset=Range.objects.all(),
        required=False,
        widget=admin.widgets.FilteredSelectMultiple("ranges", is_stacked=False))

    class Meta:
        model = Product


class MyProductAdmin(admin.ModelAdmin):

    def save_model(self, request, obj, form, change):
        # Save first to obtain id
        super(MyProductAdmin, self).save_model(request, obj, form, change)
        # Clean and re-add related objects
        obj.range_set.clear()
        for range in form.cleaned_data['ranges']:
             obj.range_set.add(range)

    def get_form(self, request, obj=None, **kwargs):
        if obj:
            ProductForm.base_fields['ranges'].initial = [o.pk for o in obj.range_set.all()]
        else:
            ProductForm.base_fields['ranges'].initial = []
        return ProductForm

# unregister and register again
admin.site.unregister(Product)
admin.site.register(Product, MyProductAdmin)