3

我有两个模型,“产品”和“范围”,由多对多字段链接。“产品”类在我没有编写的应用程序中,因此无法修改(我可以为它编辑模型管理员)。我想让“范围”和“产品”在管理员中是可编辑的,我想用 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 变得不必要地复杂)。

4

1 回答 1

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)
于 2013-11-13T12:03:02.930 回答