一个更好的 Django 管理员 ManyTomany 字段小部件

我发现 Django 管理员的默认 models.ManyToManyField小部件使用起来很麻烦。它是 HTML 选择元素,如果你有很多“其他”模型的对象,那么实际上找到你想与“这个”对象关联的“其他”对象是不切实际的。如果你有 很多的对象的“其他”模型,它似乎甚至减慢了管理页面的呈现。

我知道我可以建立自己的自定义管理小部件,并应用到我的 ManyToManyFields,因为我认为适合,但是有没有任何预先建立的,我可能会使用呢?在我的梦中,我描绘了一个自动完成文本输入的 HTML 小部件。这在 Django 管理框架中是否可行?

谢谢。

39430 次浏览

you could try using a raw id in the admin. and the django docs: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields

if you are looking for something with auto-complete you might want to look at this as a starting point http://code.djangoproject.com/wiki/AutoCompleteSolutions

and finally a very simplistic inline Example:

models.py

class SomeModel(models.Model):
users = models.ManyToMany(User)

admin.py:

class SomeModelAdmin(admin.ModelAdmin):
raw_id_fields = ("users",)

Try using the filter_horizontal attribute on your admin class, for example:

class SomeModelAdmin(admin.ModelAdmin):
filter_horizontal = ('users',)

As mentioned in the documentation, "adding a ManyToManyField to this list will instead use a nifty unobtrusive JavaScript "filter" interface that allows searching within the options". filter_vertical does the same thing with a slightly different layout.

I haven't actually played with it but I found this promising looking library referenced elsewhere.

It appears to do exactly what I wanted. Rather than loading the entire list of related objects (regardless of how many there are!) and presenting you with a picker to select a few of them, as filter_horizontal does, it presents a search/filter box and uses typeahead/autocomplete calls to retrieve results dynamically. This is great for the case where you have maybe 5000 users and want to pick 3 or 4 of them without waiting for 5k <option> elements to download and render.

This is an old question, but I want to add an answer here for people who find this just like I did: this situation is exactly what Django inline admins are for. Specifically, I use TabularInlines with raw id fields for many-to-many relations that have too many choices.

https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#django.contrib.admin.TabularInline

You can try using Inline model as such -

class ManyToManyInline(TabularInline):
model = MyModel.many_to_many_field_name.through
raw_id_fields = ("render_raw_id_using_this",)


@register(MyModel)
class YourAdminClass(AnyBaseClass):
exclude = ("many_to_many_field_name",)
inlines = (ManyToManyInline,)

Now there is another issue I faced, finding "render_raw_id_using_this" field name.

So, I moved to shell and tried finding fields in through model as such -

In [1]: MyModel.many_to_many_field_name.through._meta.fields
Out [1]: (<django.db.models.fields.AutoField: id>, <django.db.models.fields.related.ForeignKey: fieldname1>, <django.db.models.fields.related.ForeignKey: fieldname2>)

So, I replaced render_raw_id_using_this with fieldname1

Similarly, you can use these field names to render raw id instead of drop down list in Inline model.