Django:如何将基于函数的视图重新创建为(通用编辑)Class 基于视图

Django: how to re-create my function-based view as a (Generic Editing) Class Based View

我有一个基于函数的视图,目前运行良好。但是,我想学习如何使用通用的 UpdateView class 创建此函数的等效基于 Class 的视图版本——尽管我想解决方案,无论它是什么,对于同样创建视图。

我通常知道如何创建和使用基于 Class 的视图,但是我的基于函数的视图中有一行我无法在相应的 UpdateView 中工作——像往常一样通用编辑 Class 基于视图,目前还不清楚我需要覆盖哪种方法才能插入所需的功能。

可以说,我无法移植到 CBV 的特定任务是覆盖查询集的一行,该查询集将用于显示特定字段,该字段定义为 ForeignKey 到我数据库中的另一个模型。

首先,基于工作功能的视图,突出显示我无法在 CVB 版本中工作的特定代码位:

@login_required
def update_details(request, pk):
    """update details of an existing record"""
    umd_object = UserMovieDetail.objects.select_related('movie').get(pk=pk)

    movie = umd_object.movie

    if umd_object.user != request.user:
        raise Http404

    if request.method != 'POST':
        form = UserMovieDetailForm(instance=umd_object)

        # this is the single line of code I can't get working in UpdateView version:

        form.fields['user_guess'].queryset = User.objects.filter(related_game_rounds=movie.game_round)

    else:
        form = UserMovieDetailForm(instance=umd_object, data=request.POST)
        if form.is_valid():
            form.save()

            return redirect(movie)

    context = {'form': form, 'object': umd_object }
    return render(request, 'movies/update_details.html', context)

我可以在 UpdateView 中成功地重新创建这个基于函数的视图的每个部分除了这一行(为清楚起见从上面复制):

    form.fields['user_guess'].queryset = User.objects.filter(related_game_rounds=movie.game_round)

此行的作用:外键的默认表单字段是 ModelChoiceField,它默认显示 all 个对象相关型号。我上面的代码覆盖了该行为,并说:我只希望表单显示这组过滤后的对象。只要我使用这个基于函数的视图,它就可以正常工作。

旁注: 我知道可以通过修改我的 forms.py 文件中的 ModelForm 本身来实现此结果。这个问题的目的是更好地理解如何使用内置的基于通用 Class 的视图,使它们能够重新创建我已经可以使用基于函数的视图实现的功能。所以,请不要用“你为什么不直接在表单中这样做”来回答我的问题——我已经知道这个选项,这不是我要解决的问题,特别是。

现在是 UpdateView(同样,我认为 CreateView 也是一样)。首先,它看起来基本上是这样的:

class UpdateDetailsView(LoginRequiredMixin, UpdateView):
    model = UserMovieDetail
    template_name = 'movies/update_details.html'
    form_class = UserMovieDetailForm

    login_url = 'login' # used by LoginRequiredMixin

    # what method do I override here, to include that specific line of code, which needs
    # to occur in the GET portion of the view?    

    def get_success_url(self):
        return reverse('movies:movie', kwargs={'pk': self.object.movie.pk, 'slug': self.object.movie.slug })

以上是我基于函数的视图的工作重新创建,复制了所有行为 除了 过滤特定字段的 ModelChoiceField 显示结果的重要行显示在表格。

如何让这行代码在此 UpdateView 中运行?我已经在 classy class-based views 网站上查看了 UpdateView 内置的方法,然后尝试(通过纯粹的猜测)覆盖 get_form_class 方法,但我没有用,我基本上是在黑暗中开始拍摄。

请注意,由于我要重新创建的功能是关于在表单的 ModelChoiceField 中显示项目,因此所需的行为适用于视图的 GET 部分,而不是 POST。所以我需要能够在第一次呈现表单之前覆盖表单字段,就像我在基于函数的视图中所做的那样。我可以在 UpdateView 中的何处以及如何执行此操作?

首先,与形式无关的注意事项 - 来自 raise Http404 功能视图 我了解到您希望允许用户仅访问他自己的电影。对于基于 class 的视图,您可以覆盖 get_queryset 方法:

class UpdateDetailsView(LoginRequiredMixin, UpdateView):
    def get_queryset(self):
        return UserMovieDetail.objects \
            .filter(user=request.user) \
            .select_related('movie')

现在让我们开始自定义表单。

选项 1 - .get_form()

您可以覆盖 UpdateView 的 get_form 方法:

class UpdateDetailsView(LoginRequiredMixin, UpdateView):
    form_class = UserMovieDetailForm

    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        # add your customizations here
        round = self.object.movie.game_round
        form.fields['user_guess'].queryset = \
            User.objects.filter(related_game_rounds=round)
        return form

选项 2 - 移动自定义以形成 class 和 .get_form_kwargs()

您可能更愿意将自定义逻辑从视图移动到表单。为此,您可以覆盖表单的 __init__ 方法。如果自定义逻辑需要额外的信息(例如,queryset 取决于当前用户),那么您还可以覆盖 get_form_kwargs 方法以将额外的参数传递给表单:

# views.py
class UpdateDetailsView(LoginRequiredMixin, UpdateView):
    form_class = UserMovieDetailForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs.update({'current_user': self.request.user})
        return kwargs


# forms.py
class UserMovieDetailForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.current_user = kwargs.pop('current_user')
        super().__init__(*args, **kwargs)
        # add your customizations here
        self.fields['user_guess'].queryset = ...

P.S。一般来说,了解基于 django class 的视图的重要资源是 https://ccbv.co.uk/