Django:在模板中显示用户之前对 ModelForm 的选择
Django: Display user's previous choices for a ModelForm in the template
我正在尝试创建一个用户个人资料页面,用户可以在其中查看和更新他们对某些事物的偏好,例如他们是否是素食主义者,或者是否有特定的过敏症等。我希望数据以表格形式显示,他们当前的偏好已经填充了表单字段。
所以我创建了以下模型:
class FoodPreferences(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) # One user has one set of food prefs
vegetarian = models.BooleanField()
vegan = models.BooleanField()
...
在我的 forms.py:
中引用了
class FoodPreferencesForm(forms.ModelForm):
class Meta:
model = FoodPreferences
exclude = ('user', )
我试过创建一个继承 FormView
的视图,然后引用表单,如下所示:
class UserProfileView(generic.FormView):
template_name = "registration/profile.html"
form_class = FoodPreferencesForm
success_url = reverse_lazy('user_profile')
这将表单正确地保存到模型的一个实例中,但显然它只是在更新后再次显示空白表单,因此用户不知道他们当前的偏好是什么。
为了实现这个,我想我可能需要重写 get()
和 post()
来为用户获取 FoodPreferences
的实例,然后像你一样将这些值传递到表单中将是一个 request.POST
对象。但是,首先,我不知道该怎么做,其次,我将负责正确更新数据库,FormView
已经在这样做了。
这就是我得到的解决方案:
def get(self, request, *args, **kwargs):
prefs = FoodPreferences.objects.get(user=request.user)
form = self.form_class(prefs)
return render(request, self.template_name, {'form': form, })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if not form.is_valid():
return render(request, self.template_name, {'form': form, 'error': 'Something went wrong.'})
curr_prefs = FoodPreferences.objects.update_or_create(form.fields)
prefs.save()
return render(request, self.template_name, {'form': form, })
但我在 get()
:
的行中得到 TypeError: argument of type 'FoodPreferences' is not iterable
form = self.form_class(prefs)
因为它不需要模型实例。
我的思考方式是否正确?这似乎是一个很常见的问题,Django 会内置一些东西来解决这个问题,但我找不到任何东西。
您应该很少需要在基于 class 的视图中定义 get
或 post
,您绝对不需要在这里。
首先,您需要为您的视图使用更合适的基础 class。在这里你想更新一个现有的项目,所以你应该使用 UpdateView。
其次,您需要告诉 class 如何更新现有对象,您可以通过定义 get_object
来完成。所以:
class UserProfileView(generic.UpdateView):
template_name = "registration/profile.html"
form_class = FoodPreferencesForm
success_url = reverse_lazy('user_profile')
def get_object(self, queryset=None):
return self.request.user.foodpreferences
# or, if you aren't certain that the object already exists:
obj, _ = FoodPreferences.objects.get_or_create(user=self.request.user)
return obj
我正在尝试创建一个用户个人资料页面,用户可以在其中查看和更新他们对某些事物的偏好,例如他们是否是素食主义者,或者是否有特定的过敏症等。我希望数据以表格形式显示,他们当前的偏好已经填充了表单字段。
所以我创建了以下模型:
class FoodPreferences(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) # One user has one set of food prefs
vegetarian = models.BooleanField()
vegan = models.BooleanField()
...
在我的 forms.py:
中引用了class FoodPreferencesForm(forms.ModelForm):
class Meta:
model = FoodPreferences
exclude = ('user', )
我试过创建一个继承 FormView
的视图,然后引用表单,如下所示:
class UserProfileView(generic.FormView):
template_name = "registration/profile.html"
form_class = FoodPreferencesForm
success_url = reverse_lazy('user_profile')
这将表单正确地保存到模型的一个实例中,但显然它只是在更新后再次显示空白表单,因此用户不知道他们当前的偏好是什么。
为了实现这个,我想我可能需要重写 get()
和 post()
来为用户获取 FoodPreferences
的实例,然后像你一样将这些值传递到表单中将是一个 request.POST
对象。但是,首先,我不知道该怎么做,其次,我将负责正确更新数据库,FormView
已经在这样做了。
这就是我得到的解决方案:
def get(self, request, *args, **kwargs):
prefs = FoodPreferences.objects.get(user=request.user)
form = self.form_class(prefs)
return render(request, self.template_name, {'form': form, })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if not form.is_valid():
return render(request, self.template_name, {'form': form, 'error': 'Something went wrong.'})
curr_prefs = FoodPreferences.objects.update_or_create(form.fields)
prefs.save()
return render(request, self.template_name, {'form': form, })
但我在 get()
:
TypeError: argument of type 'FoodPreferences' is not iterable
form = self.form_class(prefs)
因为它不需要模型实例。
我的思考方式是否正确?这似乎是一个很常见的问题,Django 会内置一些东西来解决这个问题,但我找不到任何东西。
您应该很少需要在基于 class 的视图中定义 get
或 post
,您绝对不需要在这里。
首先,您需要为您的视图使用更合适的基础 class。在这里你想更新一个现有的项目,所以你应该使用 UpdateView。
其次,您需要告诉 class 如何更新现有对象,您可以通过定义 get_object
来完成。所以:
class UserProfileView(generic.UpdateView):
template_name = "registration/profile.html"
form_class = FoodPreferencesForm
success_url = reverse_lazy('user_profile')
def get_object(self, queryset=None):
return self.request.user.foodpreferences
# or, if you aren't certain that the object already exists:
obj, _ = FoodPreferences.objects.get_or_create(user=self.request.user)
return obj