9

假设我们有一个名为 Closet 的应用程序,它有一些模型:

# closet.models.py
class  Outfit(models.Model):
    shirt   = models.ForeignKey(Shirt)
    pants   = models.ForeignKey(Trouser)

class Shirt(models.Model):
    desc    = models.TextField()

class Trouser(models.Model):
    desc    = models.TextField()

class Footwear(models.Model):
    desc    = models.TextField

使用通用详细视图,很容易使 URL conf 中的每个细节:

#urls.py
urlpatterns = patterns('',
    url(r'^closet/outfit/(?P<pk>\d+)$',     DetailView(model=Outfit),       name='outfit_detail'),
    url(r'^closet/shirt/(?P<pk>\d+)$',          DetailView(model=Shirt),        name='shirt_detail'),
    url(r'^closet/trouser/(?P<pk>\d+)$',        DetailView(model=Trouser),      name='trouser_detail'),
    url(r'^closet/footwear/(?P<pk>\d+)$',       DetailView(model=Footwear),     name='footwear_detail'),
)   

我接下来要做的是定义将创建每种类型的新对象的视图。我想CreateView使用能够处理预填充字段数据的扩展版本来做到这一点。

具体来说,我想要以下行为:

  1. 如果我访问/closet/outfit/new,我想获得模型的标准ModelFormOutfit其中所有内容均为空白且所有内容均可编辑。
  2. 如果我访问/closet/outfit/new/?shirt=1,我想查看我在案例 1) 中看到的所有字段,但我希望衬衫字段预先填充 pk=1 的衬衫。此外,我希望将衬衫字段显示为不可编辑。如果表单已提交并被视为无效,则在重新显示表单时,我希望衬衫字段继续不可编辑。
  3. 如果我访问/closet/outfit/new/?shirt=1&trouser=2,我想查看我在案例 1) 中看到的所有字段,但现在衬衫和裤子字段都应该预先填充且不可编辑。(即只有footwear字段应该是可编辑的。)

一般来说,这可能吗?即查询字符串可以这样修改显示表单的结构吗?我想以尽可能 DRYest 的方式完成此任务。我的直觉告诉我,这对于基于类的视图应该是可行的,并且可能会涉及model_form_factory,但我无法在脑海中直接理解逻辑。特别是,我不确定在构建时是否可以让基于类的视图访问request.REQUEST(即request.POSTrequest.GET参数) 。ModelForm

也许只有当我对锁定字段使用不同的查询字符串关键字时才有可能。即,URL 可能需要是:/closet/outfit/new/?lock_shirt=1/closet/outfit/new?lock_shirt=1&lock_trouser=2。也许如果以这种方式完成,POST处理程序将同时获得锁定字段列表(用于在浏览器中显示表单)以及所有模型字段的常规列表,以实际创建对象。

为什么我想要这个:在模板中footwear_detail我希望能够制作一个像

<a href="{% url outfit_new %}?footwear={{object.pk}}>Click to create a new outfit with this footwear!</a>

一般来说,能够链接到“结构”(不仅仅是值)根据传递的查询字符串而变化的表单非常有用。


回应 Berislav Lopac 的伟大建议:

所以我继续做了:

class CreateViewWithPredefined(CreateView):
    def get_initial(self):
    return self.request.GET

这可以满足我 90% 的需求。但是,让我再详细说明一下情况。假设我在 Outfit 模型中添加了两个字段:headgear = models.ManyToManyField('headgear')awesomeness_rating = models.FloatField().

两个问题:

  1. 如果我访问/closet/outfit/new/?awesomeness_rating=10,那么我的表格会预先填写[u'10']而不是仅填写10. 是否有我应该在我的模板中使用的过滤器或者我可以添加到我的视图中以使格式更合适的一些处理?
  2. 如果我想预先指定几件头饰,通过查询字符串传递感觉像 python 列表的正确格式是什么?即我应该做什么/closet/outfit/new/?headgear=1,2,3?如果是这样,Django 会正确地确定我想预先选择带有这些 ID 的 3 件头饰吗?

继续在这方面工作……

class CreateViewWithPredefined(CreateView):
    def get_initial(self):
        initial = super(CreateView, self).get_initial()
        for k, v in self.request.GET.iterlists():
            if len(v) > 1:
                initial.update({ k : v })
            else:
                initial.update({ k : v[0] })
        return initial

这似乎用一块石头杀死了 2 只鸟:数字数据从 unicode 强制转换为数字,并在可能的情况下(如预期的那样)使列表变平。需要检查这是否适用于多值字段。

4

1 回答 1

4

self.request位于 CBV 中的任何位置。:-)

好的,让我让这个答案更全面。基本上,您想要的是由FormMixinget_initial贡献的方法。覆盖它以填充字段的初始值。

于 2013-06-19T16:01:32.910 回答