我可以在基于类的视图中使用duck-typing

时间:2013-11-08 02:08:21

标签: django django-class-based-views

我可能完全不在这里预订。 (如果我是,请随时告诉我。)

我的用例是我有一份学校名单。学校模式很简单:

class School(models.Model):
    name = models.CharField(max_length=100)
    mascot = models.CharField(max_length=100, null=True, blank=True)

当我的用户想要编辑其中一所学校时,我不希望他们编辑主副本。相反,我想给他们自己的副本,他们可以玩。完成编辑后,他们可以提交更改,其他人也会批准。所以我有另一个类用于学校用户的副本:

class UserSchool(models.Model):
    name = models.CharField(max_length=100)
    mascot = models.CharField(max_length=100, null=True, blank=True)
    master_school = models.ForeignKey(School)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)

所以我设置了一个表单来处理UserSchool的编辑:

class UserSchoolForm(forms.ModelForm):
    class Meta:
        model = UserSchool
        fields = ['name','mascot']

现在我有了EditSchool表格:

class EditSchool(UpdateView):
    model = School
    success_url = reverse_lazy('list_schools')
    form_class = UserSchoolForm

    def get(self, request, *args, **kwargs):
        school = self.get_object()

        # make a copy of the school for this user
        user_school, created = UserSchool.objects.get_or_create(
            master_school=school, user=request.user,
            defaults={'name' : school.name, 'mascot' : school.mascot})

        self.object = user_school
        form = UserSchoolForm()
        context = self.get_context_data(form=form)
        return self.render_to_response(context)

我知道get()正确地复制了副本,但是当表单显示时,“name”或“default”字段中没有列出值。我怀疑问题在于cls.model = School,但self.object是UserSchool的一个实例。

我是否关闭但遗漏了什么?我完全走错了路吗?有没有更好的模型(比如有一个具有“master”特殊用户的School实例)?

(还有一个小的复杂因素 - 因为我是Django的老手,但新的基于类的视图,我正在尝试使用Vanilla Views,因为我发现更容易弄清楚发生了什么。)< / p>

1 个答案:

答案 0 :(得分:0)

只是为了排除显而易见的事实 - 你没有向表单构造函数传递任何东西。你用instance=user_school试过了吗?可能有更多需要工作但我会从那里开始。

要稍微扩展一下 - 在您的视图中,您完全覆盖了内置的get方法。这没关系,但这意味着你绕过了视图超类的一些自动行为。具体来说,get(您的一个祖先类)的ProcessFormView方法使用视图类的get_form方法实例化表单。 FormMixin,另一个祖先,定义get_form

return form_class(**self.get_form_kwargs())

get_form_kwargs上的ModelFormMixinself.object添加到表单的kwargs

kwargs.update({'instance': self.object})

由于被覆盖的get方法未调用get_form,因此它也不会调用get_form_kwargs,因此不会遍历为表单提供初始绑定的整个路径

我个人会尝试通过修改自定义视图的get_object方法并将其余视图单独处理来解决此问题:

class EditSchool(UpdateView):
    model = School
    success_url = reverse_lazy('list_schools')
    form_class = UserSchoolForm

    def get_object(self, queryset=None):
        school = super(EditSchool, self).get_object(queryset=queryset)
        user_school, created = UserSchool.objects.get_or_create(
            master_school=school, user=self.request.user,
            defaults={'name' : school.name, 'mascot' : school.mascot})
        return user_school

可能需要进行更多更改 - 我尚未对此进行测试 - 但getset方法都使用get_object,并根据需要将其绑定到表单。