更新:解决方案可以作为单独的答案找到
我正在制作一个Django表单,允许用户将tvshows添加到我的数据库中。为此,我有Tvshow
模型,TvshowModelForm
,我使用基于类的通用视图CreateTvshowView
/ UpdateTvshowView
来生成表单。
现在出现了我的问题:假设用户想要向数据库添加节目,例如权力的游戏。如果此标题的节目已经存在,我想提示用户确认这确实是与db中的节目不同的节目,如果不存在类似节目,我想将其提交给数据库。我如何才能最好地处理此确认?
我的一些实验显示在下面的代码中,但也许我会以错误的方式解决这个问题。我的解决方案的基础是包含一个隐藏字段force
,如果用户得到提示他是否确定要提交此数据,则该字段应设置为1,以便我可以读出此事是否为1判断用户是否再次点击提交,从而告诉我他想存储它。
我很想听听你们如何解决这个问题。
views.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)
答案 0 :(得分:2)
在这里作为答案发布的想法帮助解决了这个问题,特别是Alexander Larikov和Chris Lawlor的想法,我想发布我的最终解决方案,以便其他人可以从中受益。
事实证明可以用CBV做到这一点,我更喜欢它。 (因为我是保持一切OOP的粉丝)我也使表格尽可能通用。
首先,我做了以下表格:
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
我希望这会使有类似问题的人受益。
答案 1 :(得分:1)
您可以将POST数据粘贴到用户的会话中,重定向到包含简单的确认/拒绝表单的确认页面,该表单将POST到另一个处理确认的视图。如果确认更新,请将POST数据拉出会话并正常处理。如果取消更新,请从会话中删除数据并继续。
答案 2 :(得分:1)
我会将其作为答案发布。在表单的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")
答案 3 :(得分:1)
我必须做类似的事情,我可以使用Jquery Dialog(显示表单数据是否会“重复”)和Ajax(发布到进行必要验证的视图,如果出现问题或返回)不)。如果数据可能重复,则会显示一个对话框,其中显示重复的条目,并且它有2个按钮:确认或取消。如果有人点击“确认”,您可以继续原始提交(例如,使用jquery提交表单)。如果没有,您只需关闭对话框并按原样放置。
我希望它有所帮助,你理解我的描述......如果你需要帮助,请告诉我,我可以复制你的例子。
答案 4 :(得分:0)
另一种方法是使用Django的内置表单向导功能,并且比使用vaidationerror更为简洁:https://django-formtools.readthedocs.io/en/latest/wizard.html 这样一来,您就可以将多个表单链接在一起,并在所有表单都通过验证后对其进行操作。