【问题标题】:In django admin how do I add a field for the reverse side of a ManyToManyField在 django admin 中,如何为 ManyToManyField 的背面添加一个字段
【发布时间】:2013-02-05 18:08:44
【问题描述】:

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

如果我可以修改 Products,我可以使用现有的直通表在其上放置 ManyToManyField,这可以正常工作,但如前所述,我不能(或不会,因为它会使对外部应用程序的升级成为现实痛)。

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

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

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

    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)
    

    【讨论】:

    • 非常感谢,我想出了类似的东西,打算将其发布为答案,但现实生活阻碍了。
    猜你喜欢
    • 2012-04-10
    • 2023-01-13
    • 1970-01-01
    • 2019-01-28
    • 2018-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    相关资源
    最近更新 更多