Django 的自带后台admin中多于manytomany类型可以进行如下定制:
models.py
# coding:utf-8
from django.db import models
from django.core.urlresolvers import reverse
class Ingredient(models.Model):
# dish = models.ManyToManyField(Dishes, verbose_name=u'菜品')
name = models.CharField(verbose_name=u'食材名称', max_length=128)
tip = models.TextField(verbose_name=u'备注说明', blank=True)
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse('ingredient_detail', kwargs={'pk': self.pk})
class Dishes(models.Model):
name = models.CharField(verbose_name=u'菜品名称', max_length=250)
description = models.TextField(verbose_name=u'介绍', blank=True)
create_date = models.DateField(verbose_name=u'加入时间', auto_now_add=True)
last_date = models.DateField(verbose_name=u'最后编辑时间', auto_now=True)
ingredient = models.ManyToManyField(Ingredient, verbose_name=u'食材列表')
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse('dishes_display_detail', kwargs={'pk': self.pk})
admim.py
from django.contrib import admin
from dishes.models import *
class IngredientInline(admin.TabularInline):
model = Ingredient
class StepInline(admin.TabularInline):
model = Step
class DishesAdmin(admin.ModelAdmin):
inlines = [StepInline, ]
filter_horizontal = ('ingredient',)
admin.site.register(Dishes, DishesAdmin)
admin.site.register(Ingredient)
会得到如下的多选插件
个人觉得这个很爽。比其他Bootstrap Dual Listbox是要难看点,不过也好用,而且本身就在Django里,so尝试用在自己代码中。不过问题是,搜索了下好像还没人这么做过。所以开始一下历程。
forms.py
from django import forms
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin.widget import FilteredSelectMultiple
from .models import *
class MyFilteredSelectMultiple(FilteredSelectMultiple):
'''
这里手动添加Ingredient,那个绿色的小加号。在源代码中没看出来是在哪里生成的,有网友知道的话还麻烦告诉我下。
'''
def render(self, name, value, attrs=None, choices=()):
output = [super(MyFilteredSelectMultiple, self).render(name, value, attrs, choices)]
output.append(
'<a href="/dishes/ingredient/add/" class="add-another" id="add_id_ingredient" οnclick=" \
return showAddAnotherPopup(this);"><img src="/static/admin/img/icon_addlink.gif" width="10" height="10" \
alt="00"></a><br>'
)
return mark_safe(''.join(output))
class DishesEditForm(forms.ModelForm):
ingredient = forms.ModelMultipleChoiceField(queryset=Ingredient.objects.all(),
label=u'控件显示lable,对应于model的verbose_name',
widget=MyFilteredSelectMultiple(
verbose_name=u'多选控件两栏显示的标题名称',
is_stacked=False,
attrs={}
),
required=False
)
class Meta:
model = Dishes
fields = '__all__'
widgets = {
}
labels = {
'name': _(u"菜品名称~!哟"),
}
help_texts = {
'name': _(u'Help Dishes name')
}
error_messages = {
'name': {
'max_length': _(u'必须在125个字以内'),
}
}
view.py
from django.views.generic import UpdateView
from .form import DishesEditForm
from .models import *
class DishesEdit(UpdateView):
model = Dishes
form_class = DishesEditForm
template_name = 'dishes_edit.html'
dishes_edit.html
<html>
<head lang ="en">
<span style="white-space:pre"> </span><meta charset = "utf-8">
<span style="white-space:pre">{% load static %}
<link rel="stylesheet" type="text/css" href="{% static "admin/css/base.css" %}" />
<!--[if lte IE 7]>
<link rel="stylesheet" type="text/css" href="{% static "admin/css/ie.css" %}" />
<![endif]-->
<script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% static "admin/" %}{% endfilter %}";</script></span>
<link rel="stylesheet" type="text/css" href="/static/admin/css/forms.css">
<link rel="stylesheet" type="text/css" href="/static/admin/css/widgets.css">
<script type="text/javascript">window.__admin_media_prefix__ = "/static/admin/";</script>
<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.js"></script>
<script type="text/javascript" src="/static/admin/js/inlines.js"></script>
{{ form.media }}
<meta name="robots" content="NONE,NOARCHIVE">
</head>
<body>
<span style="white-space:pre"> </span><fieldset class="module">
<table>
{{ form.as_table }}<br>
</table>
<span style="white-space:pre"> </span>{# {{form.ingredient #}
</fieldset>
</body>
</html>
最后就是这样了,还凑合。