Django:在模板中显示用户先前对ModelForm的选择

时间:2018-09-16 12:44:23

标签: django forms django-models modelform

我正在尝试创建一个用户个人资料页面,用户可以在其中查看和更新​​他们对某些事物的偏好,例如他们是否素食,或是否有特殊过敏等。我希望数据以表格形式显示,它们的当前首选项已经填充了表单字段。

因此,我创建了以下模型:

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()
    ...
在我的form.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, })

但是我在TypeError: argument of type 'FoodPreferences' is not iterable的行上得到了get()

form = self.form_class(prefs)

因为它不期望模型实例。

我是否以正确的方式考虑这个问题?这似乎是一个很常见的问题,Django会内置一些东西来做,但是我什么也找不到。

1 个答案:

答案 0 :(得分:0)

您只需要很少在基于类的视图中定义getpost,而您肯定不需要在这里。

首先,您需要为视图使用更合适的基类。在这里您要更新现有项目,因此应该使用UpdateView。

第二,您需要告诉类如何获取现有对象以进行更新,这可以通过定义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