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/
我有一个基于函数的视图,目前运行良好。但是,我想学习如何使用通用的 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/