问题
Im trying to learn class-based views, for a detail or list view is not that complicated.
I have a search form and I just want to see if I send a query to show up the results.
Here is the function code (is not mine, is from a django book):
def search_page(request):
form = SearchForm()
bookmarks = []
show_results = False
if 'query' in request.GET:
show_results = True
query = request.GET['query'].strip()
if query:
form = SearchForm({'query': query})
bookmarks = Bookmark.objects.filter(title__icontains=query)[:10]
show_tags = True
show_user = True
if request.is_ajax():
return render_to_response("bookmarks/bookmark_list.html", locals(), context_instance=RequestContext(request))
else:
return render_to_response("search/search.html", locals(), context_instance=RequestContext(request))
Ignoring the ajax fact (just to make the problem easier for now), how can I translate this to class-based views?
I quick tried something like this:
class SearchPageView(FormView):
template_name = 'search/search.html'
def get(self, request, *args, **kwargs):
form = SearchForm()
self.bookmarks = []
self.show_results = False
if 'query' in self.request.GET:
self.show_results = True
query = self.request.GET['query'].strip()
if query:
form = SearchForm({'query': query})
self.bookmarks = Bookmark.objects.filter(title__icontains=query)[:10]
return super(SearchPageView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(SearchPageView, self).get_context_data(**kwargs)
context.update({
'show_tags': True,
'show_user': True,
'show_results': self.show_results,
'bookmarks': self.bookmarks
})
return context
Doesn't work, I get a: "'NoneType' object is not callable"
Fair enough, I started today with this stuff.
So, what's the way to make a Class-based views that can manage a get (and a post too if needed) request?
I have another example:
@render_to('registration/register.html')
def register_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('/accounts/register/success/')
else:
form = RegistrationForm()
return locals()
Would this be "transformed" the same way that the first one? Or they extend differents Views?
Im confused a lot. I don't know if the first is ProcessFormView and the second FormView or what.
Thanks.
EDIT: Solution I ended with:
class SearchPageView(FormView):
template_name = 'search/search.html'
def get(self, request, *args, **kwargs):
self.bookmarks = []
self.show_results = False
form = SearchForm(self.request.GET or None)
if form.is_valid():
self.show_results = True
self.bookmarks = Bookmark.objects.filter(title__icontains=form.cleaned_data['query'])[:10]
return self.render_to_response(self.get_context_data(form=form))
def get_context_data(self, **kwargs):
context = super(SearchPageView, self).get_context_data(**kwargs)
context.update({
'show_tags': True,
'show_user': True,
'show_results': self.show_results,
'bookmarks': self.bookmarks
})
return context
I leave this here to someone with same question :)
回答1:
The default behaviour of the FormView class is to display an unbound form for GET
requests, and bind the form for POST
(or PUT
) requests. If the bound form is valid, then the form_valid
method is called, which simply redirects to the success url (defined by the success_url
attribute or the get_success_url
method.
This matches the example quite well. You need to override the form_valid
method to create the new User
, before calling the superclass method to redirect to the success url.
class CreateUser(FormView):
template_name = 'registration/register.html'
success_url = '/accounts/register/success/'
form_class = RegistrationForm
def form_valid(self, form):
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return super(CreateUser, self).form_valid(form)
Your first example does not match the flow of FormView
so well, because you aren't processing a form with POST
data, and you don't do anything when the form is valid.
I might try extending TemplateView
, and putting all the logic in get_context_data
.
Once you get that working, you could factor the code that parses the GET data and returns the bookmarks into its own method. You could look at extending ListView
, but I don't think there's any real advantage unless you want to paginate results.
回答2:
Note, an answer here (Updating context data in FormView form_valid method?) solved this problem like this:
class ContextFormView(FormView):
template_name = 'some_template.html'
success_url = '...'
form_class = ClassOfTheForm
def get(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
context = self.get_context_data(**kwargs)
context['form'] = form
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form, **kwargs)
else:
return self.form_invalid(form, **kwargs)
def form_invalid(self, form, **kwargs):
context = self.get_context_data(**kwargs)
context['form'] = form
# here you can add things like:
context[show_results] = False
return self.render_to_response(context)
def form_valid(self, form, **kwargs):
context = self.get_context_data(**kwargs)
context['form'] = form
# here you can add things like:
context[show_results] = True
return self.render_to_response(context)
This worked perfect for me. (same issue as in this question)
As stated above, this is not my solution, if you want to give somebody credits, go to the answer in the link and give this person the credits! (Updating context data in FormView form_valid method?)
来源:https://stackoverflow.com/questions/8903601/how-to-process-a-form-via-get-or-post-using-class-based-views