Does anyone know why the following renders my template ok:
c= {'render_form' : form }
return render(request, 'page1.html', c)
but the following does not render the csrf token:
c= Context({'render_form' : form})
return render(request, 'page1.html', c)
The template looks like this:
<form method="post">
{% csrf_token %}
{{ render_form }}
<input type="submit" value="Submit" class='btn' id="submitbutton" name="_submit" />
</form>
I want to keep render() and I would like to avoid using locals().
Depends on your Django version, but the render method used to take two context related arguments, context and context_instance, the latter expects a Context or RequestContext object, the first a dictionary. The documentation has some specific deprecation details:
https://docs.djangoproject.com/en/1.8/topics/http/shortcuts/#optional-arguments
Related
I need to create function based or class based view which can edit/update multiple forms in one page. How to create this?
You should be able to have more than one form appear on a template by passing two different form variables in the view. Something like this:
def formview(request):
if request.method == 'POST'
form1 = form.Form1()
form2 = form.Form2()
context = {'form1': form1, 'form2': form2}
Then in your template you simply need to handle each form within the form tags like so:
<form action="" method="post">
{% csrf_token %}
{{ form1.as_p }}
{{ form2.as_p }}
<input class="btn btn-primary" type="submit" value="Submit">
</form>
This is my view function: It takes one kwarg i.e block_id
def write_comment(request, block_id):
block=get_object_or_404(Block, pk=block_id)
if request.method=='POST':
form=Comment_form(request.POST)
if form.is_valid():
#do stuff
else:
return render(request,'writers_block/index.html', {'comment_form':form, 'block_form':Block_form()})
To access it from my template form I use:
{%for block in block_list%}
<form method="post" action="{%url 'write_comment' block_id=block.id%}">
{%csrf_token%}
{{comment_form}}
<input type="submit" value="submit">
</form>
{%endfor%}
Somehow I'm always getting a NoReverseMatch saying that write_comment with that arguments is not found:
The urlpattern is:
url(r'^write_comment', writers_block.views.write_comment, name='write_comment')
Can you help me?
Can you change your url like this and try..
url(r'^write_comment/(?P<block_id>\d+)/$', writers_block.views.write_comment, name='write_comment')
How to avoid producing html files with content like this:
<form action="/contact/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Can I define somehow it in views or forms, so that there is no need for creating this files in templates?
Most class-based views use the TemplateResponseMixin. You can override the render_to_response method to return a HttpResponse object (or any subclass) that doesn't render a template.
class SimpleResponseMixin(object):
def render_to_response(self, context, **kwargs):
return HttpResponse(content='<content>', content_type=kwargs.get('content_type', self.content_type))
I have a form like so:
class MyForm(forms.Form):
site = forms.ChoiceField(choices=SITE_CHOICES, label=ugettext_lazy('Site'),)
...
params = forms.MultipleChoiceField(
choices=PARAM_CHOICES,
label=ugettext_lazy('Select Parameters'),
widget=forms.CheckboxSelectMultiple()
)
And in my template:
<form action="{% url results %}" method="get">{% csrf_token %}
{% for field in myform %}
<div class="field_wrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<input type="submit" name="submit" value="{% trans 'Query' %}" />
</form>
My problem is that when I submit the form as GET the variables are like the following:
site=1¶ms=foo¶ms=bar¶ms=something&submit=Query
my params variable is clearly being overwritten by the last choice? How can get access to the submitted data as separate variables?
Any help appreciated.
Using Django forms
You should be using Django's form handling with a POST which would majke things easier. Here goes:
if request.method == 'GET':
form = MyFormClass()
else:
form = MyFormClass(request.POST)
if form.is_valid():
do_something_with(form.cleaned_data['params'])
return redirect('somewhere')
return render_to_response('my_template.html', RequestContext(request, {'form':form}))
Notes on using GET vs POST with forms
It's useless to include {% csrf_token %} if you're going to GET the form (Absolutely no csrf validation is done with GET requests, which make sense, as GET requests are supposed to be non-data-altering.
Anyway, if you're really going to GET the page, you can still use the same logic as written before, with a little tuning:
form = MyFormClass(request.GET)
if form.is_valid():
do_something_with(form.cleaned_data['params'])
return render_to_response('some_template.html', {'stuff':some_stuff})
return render_to_response('form_submission_page.html', {'form':form})
Last thing, using GET to submit data is usually bad practice, unless you're creating some search function or altering display (pagination & all).
Using request.GET
Now, if for some reason you don't want to use Django forms, you can still get around the problem and retrieve your params, you simply need to use the QueryDict.getlist instead of using the QueryDict.get method.
Here goes:
my_data = request.GET.getlist('params')
Documentation
Don't forget to check out the Django documentation on QueryDicts and on forms
And use {% csrf_token %} in get request is a bad practice.
Use form.is_valid() and form.cleaned_data['params'].
I have a form which allows users to select several parameters to allow faceted querying of data. As there is no data entry going on here I want the form to post to GET and I have a another view with a different template which displays the results.
I want the form to validate as normal so that if a required field is not completed the corresponding errors are displayed. At the moment my process looks like this (simplified):
my search view:
def search(request):
...
context['form'] = GraphForm()
...
return render(request, 'search.html', context)
my results view:
def results(request):
if 'submit' in request.GET:
# process GET variables as query
...
return render(request, 'results.html', context)
my search.html template:
<form action="{% url results %}" method="get">{% csrf_token %}
{% for field in form %}
<div class="field_wrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<input type="submit" name="submit" value="Query" />
</form>
Given that the form submits to another url with separate view code, what is the best way to go about validating (highlighting errors), and ensuring I have my GET data?
Any help much appreciated.
This might be a little late, but I think the following will work while maintaining similarity to 'POST' workflow:
Instead of having two different views for searching and displaying results, just have one view. The normal codepath described for post forms can then be followed. Instead of using request.method == 'POST' to detect form submission, we instead use 'submit' in request.GET. If using javascript to submit the form, make sure that 'submit' is included in the GET data or use a hidden field to detect form submission.
views.py
def search(request):
context_dict = {}
if 'submit' in request.GET:
form = GraphForm(request.GET)
if form.is_valid():
#do search and add results to context
#If you don't want to use a single view,
# you would redirect to results view here.
results = get_results(**form.cleaned_date)
context_dict['results'] = results
else:
form = GraphForm()
context_dict['form'] = form
return render(request, 'search.html', context_dict)
search.html
<form action="{% url 'search' %}" method="get">
{{form}}
<input type="submit" name="submit" value="Query" />
</form>
{% if results %}
{% include 'results.html' %}
{% endif %}
You should be able to pass request.GET just like request.POST to the form. The form simply accepts a data dictionary. It doesn't care where that comes from. Have you already tried that?
Use JavaScript/jQuery for form validation. All you need to do is add an id to form, and in the corresponding Javascript, do something like
document.getElementById("#form").onsubmit = checkForm();
or using jQuery
$("#form").submit(checkForm);
where checkForm() returns true upon successful validation, and false otherwise. (Note that, if you do not return false, form submission will continue as usual.)
Which fields you check for/validate can also change by using Django's templates.