Django admin: ManyToManyField in list_editable?

2019-05-14 07:39发布

In the Django admin, I would really like to be able to display an editable ManyToManyField in the list display.

It doesn't necessarily need to be the full ManyToManyField control - being able to save just one value would be good enough for the purposes of the list display (though the underlying values are many-to-many in nature).

My model looks like this:

class Item(models.Model):
    name = models.CharField(max_length=500)
    colour = models.ManyToManyField(Colour, related_name='primary_colour')

If I try this in admin.py:

class ItemAdmin(admin.ModelAdmin):
    list_display = ('name', 'colour')
    list_editable = ('colour')

Then I get this error:

'ItemAdmin.list_display[6]', 'colour' is a ManyToManyField which is not supported.

Is there any way at all that I can show an editable ManyToManyField for rapid editing in the list display?

I found this related question, which explains how to make the values visible in the list display, but not editable: ManyToManyField widget in a django admin change list?

2条回答
ゆ 、 Hurt°
2楼-- · 2019-05-14 08:15

You can easily add a custom view to your admin urls and add the required html/javascript/ajax. Here's the basics:

class ItemAdmin(admin.ModelAdmin):
    # regular stuff

    def render_foo(self, obj):
        # add this to your list_display
        html = '<stuff><input/submit action></stuff>'
        return mark_safe(html)

    def get_urls(self):
        urls = super(ItemAdmin, self).get_urls()
        extra_urls = patterns('',
            (r'^process_foo/$', self.admin_site.admin_view(self.process_foo)),
        )
        return extra_urls + urls

    def process_foo(self, request):
        if not request.is_ajax():
            raise Http404
        foo = request.GET.get("attr")
        # process m2m
        # return some json
查看更多
一夜七次
3楼-- · 2019-05-14 08:23

Django by default won't allow to add ManyToManyField in list_editable in ModelAdmin. So we need to override model admin methods.

On looking your models you need to follow below steps to get the ManyToManyField editable in list display page.

In apps/forms.py you need to define which ManyToMany fields you need to make editable in list display page. As below,

from django import forms
from app.models import Item


class ItemChangeListForm(forms.ModelForm):

    # here we only need to define the field we want to be editable
    colour = forms.ModelMultipleChoiceField(queryset=Colour.objects.all(), 
        required=False)

In app/admin.py you need to override methods of model admin. As below,

from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
from app.models import Item
from app.forms import ItemChangeListForm

class ItemChangeList(ChangeList):

    def __init__(self, request, model, list_display,
        list_display_links, list_filter, date_hierarchy,
        search_fields, list_select_related, list_per_page,
        list_max_show_all, list_editable, model_admin):

        super(ItemChangeList, self).__init__(request, model,
            list_display, list_display_links, list_filter,
            date_hierarchy, search_fields, list_select_related,
            list_per_page, list_max_show_all, list_editable, 
            model_admin)

        # these need to be defined here, and not in ItemAdmin
        self.list_display = ['action_checkbox', 'name', 'colour']
        self.list_display_links = ['name']
        self.list_editable = ['colour']


class ItemAdmin(admin.ModelAdmin):

    def get_changelist(self, request, **kwargs):
        return ItemChangeList

    def get_changelist_form(self, request, **kwargs):
        return ItemChangeListForm


admin.site.register(Item, ItemAdmin)

Now you all set to check the changes, run server and check django admin for Movie model. You can edit ManyToMany field directly from list display page.

Note : If you are going to use muliptle ManyToManyFields editable in list then, you need to set DATA_UPLOAD_MAX_NUMBER_FIELDS in settings.py .

查看更多
登录 后发表回答