这个问题看似显而易见,但过去几天我被抛出一个循环。我在django-forms上找到的绝大多数教程和文档都将它们显示为自己的独立视图。
以django 1.6官方文档为例,'Using a form in a view':
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
我遇到的问题是,我几乎从未专注于整个页面或只查看一个表单。由于上下文变量,我无法{% include %}
表单视图。如果不引入很多项目或重新处理我的所有模板和视图,我也无法{% extend %}
。
在同一视图中将表单逻辑与其他引用和变量结合起来是一个好习惯吗?我只想确认是的,这是正常的,可接受的,还是我不做的事情令人无法接受。如果我在每个需要表单的视图中执行此操作,那么看起来像是一些非DRY样板。
博客中也出现了一些争论。表单逻辑教程。很难说是修改CBV还是使用一些好的'FBV'是首选。我只是不想养成任何坏习惯,而我还是新手并且在学习。
这是我目前正在查看的“工作”代码:
def home_page(request):
all_sliders = Slider.objects.all()
all_marketing = Marketing.objects.all()
all_features = Feature.objects.all()
skill_set = Skills.objects.all()
#clunky way of adding the form...yes? no?
errors = []
if request.method == 'POST':
form = ContactForm(request.POST)
if not request.POST.get('subject', ''):
errors.append('Enter a subject.')
if not request.POST.get('message', ''):
errors.append('Enter a message.')
if request.POST.get('email') and '@' not in request.POST['email']:
errors.append('Enter a valid e-mail address.')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply@mysite.com'),
# email address where message is sent.
['email@mysite.com'],
)
return HttpResponseRedirect('frontpage/thanks/')
else:
form = ContactForm()
context = {'sliders': all_sliders, 'marketing': all_marketing,
'feature': all_features, 'skills': skill_set,
#this is tied to my form logic
'form': form, 'errors': errors,
}
return render(request, 'frontpage/home.html', context)
最后,我不想使用附加库。我正在学习django,并希望在将库用于表格之类的基本内容之前先学习它。
答案 0 :(得分:2)
使用表单为视图提供额外的上下文/诸如此类功能没有任何问题。事实上,使用CBV很容易。 docs for the Generic FormView提供了一个很好的联系表单示例,您可以通过覆盖get_context_data
来扩展它以添加额外的上下文。你不应该做的是视图中的表单验证。将它保留在forms.py中的表单类中。这是一个从文档拼凑在一起的例子:
# forms.py
class ContactForm(forms.Form):
subject = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
email = forms.CharField()
# Whatever fields you had.
def clean(self):
"""This is where you should be checking for required
fields and making sure the submitted data is safe."""
pass
def send_email(self):
# send email using the self.cleaned_data dictionary
send_mail(
self.cleaned_data['subject'],
self.cleaned_data['message'],
self.cleaned_data.get('email', 'noreply@mysite.com'),
['email@mysite.com']
)
# views.py
class HomePageFormView(FormView):
template_name = 'frontpage/home.html'
form_class = ContactForm
success_url = 'frontpage/thanks/'
def get_context_data(self, **kwargs):
context = super(HomePageFormView, self).get_context_data(**kwargs)
context['sliders'] = Slider.objects.all()
context['marketing'] = Marketing.objects.all()
context['feature'] = Feature.objects.all()
context['skills'] = Skills.objects.all()
return context
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super(HomePageFormView, self).form_valid(form)
答案 1 :(得分:1)
将表单逻辑与其他逻辑结合起来是一种很好的做法 同一视图中的引用和变量?我想 确认是的,这是正常的,可以接受的,或者我不这样做 事情令人无法接受。
在视图中向上下文添加其他内容是完全可以接受的(否则,您将如何呈现内容?)。
当您谈论表单逻辑时会遇到问题,而这里是您的代码/方法存在问题的地方。
django中有一个约定(您可以自由地违反),该表单会放在您的应用程序中的forms.py
文件中。
您可以在views.py
中完美地声明所有表单类,这种方法没有任何问题,但是一旦您开始与其他人合作,或者开始将公共django应用程序组合到您的代码中,最好使用惯例。毕竟,软件开发框架只不过是一堆约定,而且一些帮助程序都很好地捆绑在一起。
然而,您的逻辑问题更严重的一个问题是您没有使用表单验证 - 而且您必须现在绝对停止。
表单是 - 在其核心 - 验证词典的一种方式,它们是django框架最强大的功能之一。它们允许您验证任何字典,并在您使用模型或数据的任何地方使用。
您编写的代码几乎就是表单验证的作用 - 它会检查表单中是否缺少必填字段(或者,考虑另一种方式 - 字典中所需的键是None)然后添加错误消息和标记表格(或字典)无效。
使用表单的基本逻辑是这样的:
def someview(request):
form = SomeForm() # This creates an unbound (empty) form
if request.method == 'POST':
form = SomeForm(request.POST, request.FILES) # Bind the form to
# POST data
if form.is_valid():
# perform validation
# do something with form's data
data = form.cleaned_data['somefield']
# Or, if its a model form (a form that is tied to a
# model), save the model since the form is validated
obj = form.save()
# All post requests should redirect
return redirect('index')
else:
# The form was not valid, return the form
# to the view, except this time it will
# contain helpful error messages
return render(request, 'form.html', {'form': form})
else:
# Return an empty form to the view
# for the user to fill in, as this is a GET not POST
# request
return render(request, 'form.html', {'form': form})
您始终可以逐个字段地自定义表单的验证规则,也可以自定义表单中的整体数据。这在form and field validation的文档中进行了讨论。
如果我这样做的话,看起来像是一些非DRY样板 每个需要表单的视图。
新的CBV通过处理重复逻辑(继承和类的一个好处)解决了这个问题。使用FormView
时,上面粘贴的代码可以最小化到以下内容:
from django.core.urlresolvers import reverse_lazy
from django.views.generic.edit import FormView
class SomeView(FormView):
template_name = 'form.html'
form_class = SomeForm
success_url = reverse_lazy('index')
def form_valid(self, form):
data = form.cleaned_data['somefield']
return super(SomeView, self).form_valid(form)
博客中也出现了一些争论。表格教程 逻辑。难以判断是否修改CBV或使用一些好的ol' FBV是首选。我不想做任何坏习惯 还是新的和学习的。
使用FBV没有任何问题 - 它们仍然是完全有效的django。 CBV带来的好处是通用功能只写一次。我的建议是在你有基于每个视图修改的通用逻辑时使用CBV。表单是一个很好的例子,显示模型,分页,渲染简单模板,下载数据(例如,您可以有一个基础视图将对象转换为Excel,然后从任何需要提供下载功能的视图中继承) CBV的优秀候选人。