Accessing GET data from a plain HTML form in a Class-Based TemplateView is straightforward. I'm currently doing it like the following:
class SomeView(TemplateView):
template_name = 'some-template.html'
def get(self, request, *args, **kwargs):
if request.GET:
# do things...
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
But I'm wondering how I can access POST data. I have tried using get_context_data() to check for posted form data...but have been unsuccessful.
Question: Can POSTed form data from a plain HTML form (not a Django form) be accessed via a TemplateView?
There's no difference in the way the data is sent between a Django form and anything else: it's in request.POST as always.
Naturally, you need to define the post method, rather than get.
Related
I have simple view in django app, which I want to show only when one of the forms is valid. I have something like:
#login_required
#require_role('admin')
def new_package(request):
invoicing_data_form = InvoicingDataForm(instance=request.user.account.company.invoicingdata)
if invoicing_data_form.is_valid():
# all here
return HttpResponse('Form valid')
else:
logger.info("Form invalid")
return HttpResponse(json.dumps(invoicing_data_form.errors)
I always get log info message that form is invalid, however, I get nothing in
invoicing_data_form.errors
It is very strange, because I am validating this form in other view using user input data and it works just fine. Any idea?
EDIT:
Just for clarification.
I am not requesting any data from user in this form.
I am using this form to validate some model instance (this form is subclassing from ModelForm).
That's because you're not "feeding" your form.
Do this:
invoicing_data_form = InvoicingDataForm(instance=invoice, data=request.POST or None)
You have an unbound form.
https://docs.djangoproject.com/en/1.7/ref/forms/api/#bound-and-unbound-forms
A Form instance is either bound to a set of data, or unbound.
If it’s bound to a set of data, it’s capable of validating that data and rendering the form as HTML with the data displayed in the HTML.
If it’s unbound, it cannot do validation (because there’s no data to validate!), but it can still render the blank form as HTML.
To bind data to a form, pass the data as a dictionary as the first parameter to your Form class constructor:
invoicing_data_form = InvoicingDataForm(request.POST or None, instance=invoice)
If you're already giving request.POST to your form using request.POST or None, but it's still invalid without errors, check that there isn't any redirect going on. A redirect loses your POST data and your form will be invalid with no errors because it's unbound.
I got this for AuthenticationForm which needs AuthenticationForm(None, request.POST) see Using AuthenticationForm in Django
I want to expand on the answer by #yuji-tomita-tomita
I typically use a CBV approach in Django, and how I'm handling forms:
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
# do things
Reading the source code I noticed that self.get_form() using get_form_kwargs(self) to populate the form with request.POST, thus getting bound to data. So if you're overloading it like I did:
def get_form_kwargs(self):
company = self.get_company()
return {"company": company}
Make sure to call the super(), and it will finally work:
def get_form_kwargs(self):
company = self.get_company()
kwargs = super().get_form_kwargs()
kwargs.update({"company": company})
return kwargs
I have a created a view class "class Demo", which has 3 functions
def update_time()
def get_context()
def before_response()
urls.py : url(r'^demo/$', Demo.as_view(),name='demo_class'),
When i'll enter url /demo/ how will it determine which function to call from "class Demo" ?
Because Django’s URL resolver expects to send the request and associated arguments to a callable function, not a class, class-based views have an as_view() class method which serves as the callable entry point to your class. The as_view entry point creates an instance of your class and calls its dispatch() method. dispatch looks at the request to determine whether it is a GET, POST, etc, and relays the request to a matching method if one is defined, or raises HttpResponseNotAllowed if not.
just read the docs
Basically class based views are recommended when you need to handle both get and post requests at one point. For example in get method of class Register, you can render the registration form and in its post method, you can handle the form submission. If its a get request it will automatically invoke the get() method in the class, same for post request. Also you can write any common code in the dispatch() method which will be invoked for every request.eg:
class Register(View):
def dispatch(self, *args, **kwargs):
'''
common code here
'''
return super(Register, self).dispatch(*args, **kwargs)
def get(self, request):
registration_form = RegistrationForm()
return render(request, 'new.html', { 'form': registration_form })
def post(self, request):
registration_form = RegistrationForm(request.POST or None)
if registration_form.is_valid():
#save form
return HttpResponseRedirect(reverse('success-show'))
return render(request,new.html', { 'form': registration_form })
For references you can check this website.
You need to subclass a class based views, and depending on that it will have one or another method.
For example TemplateView renders a template you pass in the template_name attribute.
All class based views care about is that the attributes needed to work properly are setted. That is done via different methods. You can check the django's documentation for specifics.
For example, if you want to render a form in your template view, you will need to pass the form in the context, so you can override get_context_data() like:
def get_context_data(self, **kwargs):
context = super(DemoClass, self).get_context_data(**kwargs)
context['form'] = MyForm()
return context
There are different methods to handle different things, like querysets, objects, etc.
They are not complicated, but they are specific. If a class based view does not fit what you need, it may be easier to implement the functionality from a more general view (View, TemplateView) than forcing a more specific one to do things it is not intended for.
slightly change the url
add numbers one to three in url and put the condition in your view.
Ex.
url(r'^abc/(?P<newid>.*)$', 'class_demo'),
so your url will be like abc/1 or abc/2 or abc/3
view
def class_demo(requests, newid):
if newid==1:
update_time()
elif newid==2:
get_context()
I have the following view in my django app.
def edit(request, collection_id):
collection = get_object_or_404(Collection, pk=collection_id)
form = CollectionForm(instance=collection)
if request.method == 'POST':
if 'comicrequest' in request.POST:
c = SubmissionLog(name=request.POST['newtitle'], sub_date=datetime.now())
c.save()
else:
form = CollectionForm(request.POST, instance=collection)
if form.is_valid():
update_collection = form.save()
return redirect('viewer:viewer', collection_id=update_collection.id)
return render(request, 'viewer/edit.html', {'form': form})
It displays a form that allows you to edit a collection of images. The footer of my html contains a form that allows you to request a new image source from the admin. It submits to a different data model than the CollectionForm. Since this is in the footer of every view, I want to extract lines 5-7 of the code and turn it into a decorator. Is this possible and if so how might I go about doing that?
I would make a new view to handle the post of the form. And then stick a blank form instance in a context processor or something, so you can print it out on every page.
If you do want to make a decorator, i would suggest using class based views. That way, you could easily make a base view class that handles the form, and every other view could extend that.
EDIT:
Here's the docs on class based views: https://docs.djangoproject.com/en/dev/topics/class-based-views/intro/
Note, I would still recommend having a separate view for the form POST, but here's what your solution might look like with class based views:
class SubmissionLogFormMixin(object):
def get_context_data(self, **kwargs):
context = super(SubmissionLogFormMixin, self).get_context_data(**kwargs)
# since there could be another form on the page, you need a unique prefix
context['footer_form'] = SubmissionLogForm(self.request.POST or None, prefix='footer_')
return context
def post(self, request, *args, **kwargs):
footer_form = SubmissionLogForm(request.POST, prefix='footer_')
if footer_form.is_valid():
c = footer_form.save(commit=False)
c.sub_date=datetime.now()
c.save()
return super(SubmissionLogFormMixin, self).post(request, *args, **kwargs)
class EditView(SubmissionLogFormMixin, UpdateView):
form_class = CollectionForm
model = Collection
# you can use SubmissionLogFormMixin on any other view as well.
Note, that was very rough. Not sure if it will work perfectly. But that should give you an idea.
I have 2 separate models, Post and Comment. I use DetailView to display Post contents and I want to use a CreateView to display comment creation form on the same page. What is the cleanest way to go about that?
The only thing that comes to mind is to use custom view which both gets an object and processes comment form, but this looks too dirty:
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
if request.POST:
form = CommentForm(request.POST)
# do comment form processing here
return render(request, "post/post_detail.html", {
"object": post, "comment_form": form})
Is there any clean way to do this using class based views? Or just some way to decouple post display code from comment processing code?
It is possible to combine DetailView and CreateView. You use a class for DetailView and another class for CreateView, then you create a new class that inherits from View. This new class has a get and post method. The get method calls the DetailView while the post method calls the CreateView. Take note to use reverse_lazy for the success_url in CreateView. So basically your code should look something like this:
class PostView(DetailView):
# your code
pass ;
class CommentView(CreateView):
def get_success_url(self):
return reverse_lazy('post_detail', kwargs={'pk': self.get_object(Post.objects.all().pk})
class PostCommentView(View):
def get(self, request, *args, **kwargs):
view = PostView.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs) :
view = CommentView.as_view()
return view(request, *args, **kwargs)
So your urls.py will point to
PostCommentView
I did an override of get_success_url because it will try to go to the detail view of the new comment which doesn't exist and is not what you want to do. So the override will take you to the DetailView of the post instead.
There is an explanation in the documentation.
One option would be to use the DetailView for the Post and a templatetag to display the comment form. Have the comment form submit to a Comment CreateView that redirects to the DetailView on success.
That said, it might get a little ugly if the form is invalid. In a pinch you can always call a DetailView or its methods from one of the CreateView methods. But IMO that introduces more coupling rather than less. Or you could have a separate utility function that you can call from the CreateView to display the Post if the comment form has errors.
Another option would be to use AJAX to process the comment form (in the separate CreateView) instead of a new page load.
In the end, regardless of language or framework, there's going to be a limit to how much one can decouple a view that needs to display one object type and create another.
I have a view :
class SomeView(FormView):
form_class = SomeForm
template_name = 'app/template.html'
def get(self, request, *args, **kwargs):
form = self.form_class
return render(request, self.template_name, {form:'form'})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_Valid():
#do something here
return HttpResponseRedirect("Go somewhere from here after processing")
In the post I need to make an API call which takes data from this form. Instead of this though, I want to redirect user to another view, where he can view all the data from the form and say confirm
On submit of this confirm view I should actually make this API call.
How do I pass the form data to another view ? I can simply store the form data in a dict and pass it on from the URL, but that might expose some crucial data at the browser level.
Is there a safer way to do this ?
Thanks
Yes, there is a litle helper from django:
https://docs.djangoproject.com/en/1.5/ref/contrib/formtools/form-preview/