django admin界面处理
django的admin很强大,可以很方便管理后台数据。近期的一个网站需要处理一堆关联的数据,如果简单使用admin来管理,会碰到一些问题。
情形如下:有A和B两个model
class A(models.Model):
…class B(models.Model):
a = models.ForeignKey(A)
…
在admin界面中A比较好编辑,在数据量不多的时候,添加B也方便。但是如果A有了几千条数据,添加B的时候要从这么一堆A数据中选择一条,从可用性和系统性能方面来说都是是根本不可能的。于是django admin提供了raw_id_fields字段,ForeignKey字段使用了input编辑框,用户需要手工输入A对象的id即可,或者在弹出的对话框中对A对象集合进行筛选。
这样处理感觉不够方便,数据维护人员需要记住A的id,这很容易填错id。不希望让维护人员了解这些ID,所以就希望能够在A对象的列表界面加一个“添加B对象”字段,当点击这个字段的时候,即可调出B对象的添加界面,django admin支持这种自定义字段,在A对象中如下设置即可:
def new-B(self):
return u’<a href="/admin/xxapp/B/add/?a=%d">新建 B</a>’ % self.id
new-B.allow_tags = True
通过这种自定义的方式可以添加很多操作,链接会带到任何想执行的功能。
B对象的添加界面出来之后,不希望还要了解A对象的id,因为这是从一个A对象发起的添加操作。所以需要把A对象ID传到B的添加界面中。参数的传递只能通过GET进行了,考察了django.contrib.admin.options,他是支持GET参数的,于是就这样把A对象的ID细节给隐藏掉了。如果怕用户不小心修改了A对象的ID,则可以使用javascript将这个input编辑框给disable掉。
django admin支持添加css和javascript:如下例:
class ArticleAdmin(admin.ModelAdmin):
class Media:
css = {
"all": ("my_styles.css",)
}
js = ("my_code.js",)
B添加完成之后,还希望继续添加另外一个B,也是基于同样的A对象,点击“保存并增加另一个”,这时候GET信息丢失了,A对象ID没有了。第一反映是希望用javascript把“保存并增加另一个”的链接加上GET信息,查看了页面的源代码,是一个submit的操作,没有链接可以修改的。
input type="submit" value="保存并增加另一个" name="_addanother" /
还是到服务端来考察,在django.contrib.admin.options中查找_addanother,在response_add函数中针对_addanother进行了处理,于是事情就简单了,在B的ModelAdmin对象中重写response_add函数:
def response_add(self, request, obj, post_url_continue=’../%s/’):
if request.POST.has_key("_addanother"):
from django.utils.translation import ugettext as _
from django.utils.encoding import force_unicode
from django.http import HttpResponseRedirect
opts = obj._meta
pk_value = obj._get_pk_val()
msg = _(’The %(name)s "%(obj)s" was added successfully.’) % {’name’: force_unicode(opts.verbose_name), ‘obj’: force_unicode(obj)}
self.message_user(request, msg + ‘ ‘ + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))#新增加代码,记录下GET的信息
getinfos = request.GET.items()
gets = ‘?’
for info in getinfos:
gets += ‘%s=%s&’ % (info[0],info[1])
path = request.path + getsreturn HttpResponseRedirect(path)
return super(admin.ModelAdmin, self).response_add(request,obj,post_url_continue)
这样GET信息就可以保存下来了。
查看了django的最新版本,GET信息还是没有保存,这个不应该,提了一个ticket上去。