在Django中,如何使用Django的update_object通用视图编辑继承模型的表单?

0 投票
2 回答
1791 浏览
提问于 2025-04-11 09:26

在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.htmlform对象将是Animal,因此它不会包含狗和猫这些子类的具体信息。我该如何让Django自动将子类的表单传递给animal/animals_form.html呢?

顺便提一下,我正在使用Djangosnippets #1031来管理内容类型,所以Animal会有一个名为as_leaf_class的方法,用于返回子类。

显然,我们可以为每个子类创建表单,但这会造成很多不必要的重复(因为模板都是通用的,基本上就是{{ form.as_p }})。

另外,最好假设Animal可能是几个不相关的基类之一,它们都有同样的问题,所以理想的解决方案应该是通用的。

提前感谢你的帮助。

2 个回答

0

根据我的理解,猫和狗是放在不同的数据库表里的,可能没有一个统一的动物表。不过你现在用的是一个网址模式来处理所有的情况,这样的话你需要在某个地方区分开它们。

我建议给猫和狗使用不同的网址模式,这样它们都可以调用 'create_update.update_object' 这个功能,但要用不同的 dict。比如一个用 'model':Dog,另一个用 'model':Cat

或者你可能想要一个单独的表格,让每一条记录可以是猫也可以是狗?但我觉得这样的话,你可能不能使用继承模型来实现。

1

好的,下面是我做的事情,似乎有效而且设计合理(当然,如果有错误请指正!)。

在一个核心库里(比如说 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"),
)

现在我只需要为每个基础类创建一个独特的编辑功能,这通过装饰器来实现非常简单。

希望有人觉得这有帮助,我也很乐意听取反馈。

撰写回答