在Django中,如何使用Django的update_object通用视图编辑继承模型的表单?
在Django中,有一个叫做animals的应用,内容大致如下:
在animals/models.py文件里:
from django.db import models
from django.contrib.contenttypes.models import ContentType
class Animal(models.Model):
content_type = models.ForeignKey(ContentType,editable=False,null=True)
name = models.CharField()
class Dog(Animal):
is_lucky = models.BooleanField()
class Cat(Animal):
lives_left = models.IntegerField()
还有一个animals/urls.py文件:
from django.conf.urls.default import *
from animals.models import Animal, Dog, Cat
dict = { 'model' : Animal }
urlpatterns = (
url(r'^edit/(?P<object_id>\d+)$', 'create_update.update_object', dict),
)
那么,如何使用通用视图来编辑狗和/或猫,且使用同一个表单呢?
也就是说,传递给animals/animal_form.html的form对象将是Animal,因此它不会包含狗和猫这些子类的具体信息。我该如何让Django自动将子类的表单传递给animal/animals_form.html呢?
顺便提一下,我正在使用Djangosnippets #1031来管理内容类型,所以Animal会有一个名为as_leaf_class的方法,用于返回子类。
显然,我们可以为每个子类创建表单,但这会造成很多不必要的重复(因为模板都是通用的,基本上就是{{ form.as_p }})。
另外,最好假设Animal可能是几个不相关的基类之一,它们都有同样的问题,所以理想的解决方案应该是通用的。
提前感谢你的帮助。
2 个回答
根据我的理解,猫和狗是放在不同的数据库表里的,可能没有一个统一的动物表。不过你现在用的是一个网址模式来处理所有的情况,这样的话你需要在某个地方区分开它们。
我建议给猫和狗使用不同的网址模式,这样它们都可以调用 'create_update.update_object'
这个功能,但要用不同的 dict
。比如一个用 'model':Dog
,另一个用 'model':Cat
。
或者你可能想要一个单独的表格,让每一条记录可以是猫也可以是狗?但我觉得这样的话,你可能不能使用继承模型来实现。
好的,下面是我做的事情,似乎有效而且设计合理(当然,如果有错误请指正!)。
在一个核心库里(比如说 mysite.core.views.create_update),我写了一个装饰器:
from django.contrib.contenttypes.models import ContentType
from django.views.generic import create_update
def update_object_as_child(parent_model_class):
"""
Given a base models.Model class, decorate a function to return
create_update.update_object, on the child class.
e.g.
@update_object(Animal)
def update_object(request, object_id):
pass
kwargs should have an object_id defined.
"""
def decorator(function):
def wrapper(request, **kwargs):
# may raise KeyError
id = kwargs['object_id']
parent_obj = parent_model_class.objects.get( pk=id )
# following http://www.djangosnippets.org/snippets/1031/
child_class = parent_obj.content_type.model_class()
kwargs['model'] = child_class
# rely on the generic code for testing/validation/404
return create_update.update_object(request, **kwargs)
return wrapper
return decorator
然后在 animals/views.py 里,我有:
from mysite.core.views.create_update import update_object_as_child
@update_object_as_child(Animal)
def edit_animal(request, object_id):
pass
接着在 animals/urls.py 里,我有:
urlpatterns += patterns('animals.views',
url(r'^edit/(?P<object_id>\d+)$', 'edit_animal', name="edit_animal"),
)
现在我只需要为每个基础类创建一个独特的编辑功能,这通过装饰器来实现非常简单。
希望有人觉得这有帮助,我也很乐意听取反馈。