8

更新:解决方案可以作为单独的答案找到

我正在制作一个 Django 表单以允许用户将电视节目添加到我的数据库中。为此,我有一个Tvshow模型,TvshowModelForm并且我使用基于类的通用视图CreateTvshowView/UpdateTvshowView来生成表单。

现在我的问题来了:假设一个用户想要在数据库中添加一个节目,例如权力的游戏。如果该标题的节目已经存在,我想提示用户确认这确实是与数据库中的节目不同的节目,如果不存在类似的节目,我想将其提交给数据库。我如何最好地处理此确认?

我的一些实验显示在下面的代码中,但也许我做错了。我的解决方案的基础是包含一个隐藏字段force,如果用户收到提示是否确定要提交此数据,则应将其设置为 1,以便我可以读出此事物是否为 1 以决定用户是否再次单击提交,从而告诉我他想要存储它。

我很想听听你们对如何解决这个问题的看法。

视图.py

class TvshowModelForm(forms.ModelForm):
    force = forms.CharField(required=False, initial=0)
    def __init__(self, *args, **kwargs):
        super(TvshowModelForm, self).__init__(*args, **kwargs)

    class Meta:
        model = Tvshow
        exclude = ('user')

class UpdateTvshowView(UpdateView):
    form_class = TvshowModelForm
    model = Tvshow
    template_name = "tvshow_form.html"

    #Only the user who added it should be allowed to edit
    def form_valid(self, form):
        self.object = form.save(commit=False)
        #Check for duplicates and similar results, raise an error/warning if one is found     
        dup_list = get_object_duplicates(Tvshow, title = self.object.title)
        if dup_list:
            messages.add_message(self.request, messages.WARNING, 
'A tv show with this name already exists. Are you sure this is not the same one? Click submit again once you\'re sure this is new content'
               )
#            Experiment 1, I don't know why this doesn't work
#            form.fields['force'] = forms.CharField(required=False, initial=1)

#            Experiment 2, does not work: cleaned_data is not used to generate the new form
#            if form.is_valid():
#                form.cleaned_data['force'] = 1

#            Experiment 3, does not work: querydict is immutable
#            form.data['force'] = u'1'

        if self.object.user != self.request.user:
            messages.add_message(self.request, messages.ERROR, 'Only the user who added this content is allowed to edit it.')

        if not messages.get_messages(self.request):
            return super(UpdateTvshowView, self).form_valid(form)
        else:
            return super(UpdateTvshowView, self).form_invalid(form)
4

5 回答 5

4

解决方案

在此处作为答案发布的想法的帮助下解决了这个问题,特别是 Alexander Larikov 和 Chris Lawlor 的想法,我想发布我的最终解决方案,以便其他人可以从中受益。

事实证明,使用 CBV 可以做到这一点,我更喜欢它。(因为我喜欢保持一切面向对象)我还使表单尽可能通用。

首先,我制作了以下表格:

class BaseConfirmModelForm(BaseModelForm):
    force = forms.BooleanField(required=False, initial=0)

    def clean_force(self):
        data = self.cleaned_data['force']
        if data:
            return data
        else:
            raise forms.ValidationError('Please confirm that this {} is unique.'.format(ContentType.objects.get_for_model(self.Meta.model)))

class TvshowModelForm(BaseModelForm):            
    class Meta(BaseModelForm.Meta):
        model = Tvshow
        exclude = ('user')

"""
To ask for user confirmation in case of duplicate title
"""
class ConfirmTvshowModelForm(TvshowModelForm, BaseConfirmModelForm):
    pass   

现在制作合适的意见。这里的关键是发现 get_form_class 而不是使用 form_class 变量。

class EditTvshowView(FormView):       
    def dispatch(self, request, *args, **kwargs):
        try:
            dup_list = get_object_duplicates(self.model, title = request.POST['title'])  
            if dup_list:         
                self.duplicate = True
                messages.add_message(request, messages.ERROR, 'Please confirm that this show is unique.')
            else:
                self.duplicate = False
        except KeyError:
            self.duplicate = False
        return super(EditTvshowView, self).dispatch(request, *args, **kwargs)

    def get_form_class(self):
        return ConfirmTvshowModelForm if self.duplicate else TvshowModelForm

"""
Classes to create and update tvshow objects.
"""
class CreateTvshowView(CreateView, EditTvshowView):  
    pass

class UpdateTvshowView(EditTvshowView, UpdateObjectView):
    model = Tvshow  

我希望这将使其他有类似问题的人受益。

于 2012-08-09T12:17:49.003 回答
3

我会将其发布为答案。在表单的clean方法中,您可以按照您想要的方式验证用户数据。它可能看起来像这样:

def clean(self):
    # check if 'force' checkbox is not set on the form
    if not self.cleaned_data.get('force'):
        dup_list = get_object_duplicates(Tvshow, title = self.object.title)
        if dup_list:
            raise forms.ValidationError("A tv show with this name already exists. "
                                        "Are you sure this is not the same one? "
                                        "Click submit again once you're sure this "
                                        "is new content")
于 2012-07-31T08:10:56.283 回答
1

您可以将 POST 数据粘贴在用户会话中,重定向到包含简单确认/拒绝表单的确认页面,该表单将 POST 到另一个处理确认的视图。如果确认更新,则将 POST 数据拉出会话并正常处理。如果更新被取消,请从会话中删除数据并继续。

于 2012-07-30T20:07:56.247 回答
1

我必须做一些类似的事情,我可以使用 Jquery Dialog(以显示表单数据是否会“重复”事物)和 Ajax(发布到进行所需验证的视图并在是否存在问题时返回)来实现。如果数据可能重复,则会在出现重复条目​​的位置显示一个对话框,并且它有 2 个按钮:确认或取消。如果有人点击“确认”,您可以继续原始提交(例如,使用 jquery 提交表单)。如果没有,您只需关闭对话框并让一切保持原样。

我希望它有所帮助,并且您理解我的描述....如果您需要帮助,请告诉我,以便我可以复制您的示例。

于 2012-07-31T12:06:53.823 回答
0

比使用 vaidationerror 更简洁的替代方法是使用 Django 的内置表单向导功能:https ://django-formtools.readthedocs.io/en/latest/wizard.html 这使您可以将多个表单链接在一起并对其进行操作一旦它们都被验证。

于 2020-01-13T16:15:45.843 回答