Declacre CSRF-Token in forms.py - django

I'm using Djangos CSRF-Token the way it's mostly described on the internet:
MyFormPage.html
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
</form>
But I wonder - is there a way to include it somehow directly in the forms.py?

I don't know if this is a good practice or not, but you can do something like:
from django.middleware import csrf
class SomeForm(forms.Form):
csrfmiddlewaretoken = forms.CharField(widget=forms.HiddenInput(), initial=csrf._get_new_csrf_token())
The rendered input field will be:
<input type="hidden" name="csrfmiddlewaretoken" value="Hsw4uH5jbioQhaWrgAtGgEVp5GbnXIrayuvTqbbABaSxPbGJqksEIxVI4zJW8VVj" id="id_csrfmiddlewaretoken">

Related

Making a custom template for CreateView and UpdateView with placeholders and error validation

I'm making a generic blog while learning Django.
I have an ArticleCreateView and ArticleUpdateView, and I am trying to make a custom template that both views would share.
From what I understand, CreateView and UpdateView use the same template by default (article_form.html), which is the template I'm trying to modify.
I have the following in my models.py:
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
# def __str__ ...
# def get_absolute_url ...
In my views.py:
class ArticleCreateView(CreateView):
model = Article
fields = ['title', 'body']
template_name = 'article_form.html'
class ArticleCreateView(CreateView):
model = Article
fields = ['title', 'body']
template_name = 'article_form.html'
Having the following in my template article_form.html works:
<form method='post'>
{{ form.as_p }}
<button>
Publish
</button>
</form>
I want to make it more fancy though, with loads of CSS, and a simplified version is:
<form method='post'>
{% csrf_token %}
<fieldset class="fieldset-class">
{{ form.title.errors }}
<input
class="form-class"
type="text"
placeholder="Article Title"
name="{{ form.title.name }}"
value="{{ form.title.value }}"
/>
</fieldset>
<fieldset class="form-group">
{{ form.body.errors }}
<textarea
class="form-control"
rows="8"
placeholder="Article Body"
name="{{ form.body.name }}"
>{{ form.body.value }}</textarea>
</fieldset>
</form>
What I want is a form that:
has placeholders in empty fields (instead of labels)
has model-based error validation (max_length is respected and both fields are required without me having to specify it)
doesn't erase the entered values upon submitting
The above html does the following:
submitting with empty fields will raise the errors, and any entered values will be persisted (good)
empty fields have None instead of placeholders (issue)
Substituting object.title and object.body to form.title.value and form.body.value in the above html does the following:
submitting with empty fields will raise the errors, but also erase the entered values (issue)
empty fields have the right placeholders (good)
I have read the documentation's Built-in template tags and filters, Rendering fields manually, Rendering form error messages, Looping over the form’s fields, and Attributes of BoundField, looked for similar code on SO and GitHub, read the source rendered by {{ form.as_p }}, but I find no simple solution despite having a supposedly common usecase.
The only thing I can think of is to shove {% if %} statements everywhere to choose between placeholder and value, or to get some third-party lib like crispy-forms, but it feels like a more pythonic solution should exist.
As always, I found the answer immediately after posting the question on SO.
The built-in template filter default_if_none solves the issue:
<input
class="form-class"
type="text"
placeholder="Article Title"
name="{{ form.title.name }}"
value="{{ form.title.value|default_if_none:'' }}"
/>

How to populate existing html form with django UpdateView?

I am trying to implement a simple UpdateView, but I want to use my own template. Using djangos auto_population is working, but not what I want, because I have lots of fields formatted differently.
<form method="post" action="#">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
But I want to use my own form template which looks like this:
edit_template.html
<form class="form-horizontal" role="form" method="POST" action="{% url 'update' pk=abc %}">
{% csrf_token %}
<input name='varX' id="varX" type="text" placeholder="" class="form-class">
<input name='varY' id="varY" type="text" placeholder="" class="form-class">
</form>
views.py
class ModelUpdate(UpdateView):
model = MyModel
fields = ['varX','varY']
Now I would like that form to be populated with my object data, but the form is empty.
UpdateView is also passing the data twice to the template: One as 'object' and one as 'mymodel'.
I also tried updating
get_context_data
by adding
context.update( model_to_dict(myModelData))
But that also does not change anything.
How can I populate my custom form using djangos class-based views?
Try this:
def get_initial(self):
initial = super().get_initial()
initial['my_form_field1'] = self.request.something
return initial
Have a look at django-widget-tweaks, you first need to check for any non field errors and then loopt through the fields one by one.
https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html
This article should cover just that

How to change form layouts in Django 1.8

I have a form
Field Name: [Input Box]
I want
Field Name:
[Input Box]
How can I achieve this?
forms.py
class SearchForm(forms.Form):
search = forms.CharField()
views.py
form = SearchForm()
html_dtc = {'form':form}
return render_to_response('site/home.html', html_dtc)
home.html
<form method='POST' action=''> {% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
Thank you :)
You want a custom form rendering. You can read more about it here. For example, the following code would achieve what you're after.
<form method='POST' action=''> {% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} <br/>
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
(field.errors are added, because when you are manually rendering the form, you have to take care of error rendering as well)
Try to overide form.as_p()
class SearchForm(forms.Form):
search = forms.CharField()
def as_p(self):
"Returns this form rendered as HTML <p>s."
return self._html_output(
normal_row='<p%(html_class_attr)s>%(label)s <br> %(field)s%(help_text)s</p>',
error_row='%s',
row_ender='</p>',
help_text_html=' <span class="helptext">%s</span>',
errors_on_separate_row=True)
If this is a one off thing you can render your form manually like described here in the documentation.
Otherwise there's the django-floppyforms which gives you great control over how forms and (default) widgets are rendered.
Just define a custom layout, make it the default, use floppyforms custom Form classes (they behave exactly the same) and you're good to go.
As far as I remember some of floppyforms's functionality will also be included in Django 1.9, so look out for that, too.
Use django_crispy_forms: http://django-crispy-forms.readthedocs.org/en/latest/
In the template include {% load crispy_forms_tags %} and for the form:
{% crispy form %}
In addition, you can change the layout of the form easily, by overriding the form_class in the init function of the form:
class ContactForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_class = 'form-horizontal' # <-- leave out for vertical, or form-inline
self.helper.render_hidden_fields = True
self.helper.layout = Layout(
Div(InlineRadios('applying_for_whom'), css_class="col-xs-12"),
Div(InlineRadios('gender'), css_class='col-xs-12'),
Div('agreed_to_data_transmit', css_class="col-xs-12"),
As a bonus, if you are using bootstrap, set also set CRISPY_TEMPLATE_PACK = 'bootstrap3' so then everything is taken care of automatically for vertical bootstrap.
you can do
<form method='POST' action=''>
{% csrf_token %}
<label>Field Name:</label>
{{ form.search }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
generally I don't recommend use the HTML code generated by Django, but instead I supply what is needed by the DJANGO form.
but some are required: like the ERRORs, like the CSRF token.
let me add some examples to clarify what I am talking
<form class="*" style="*">
<label /><input name="email" />
<label /><input name="password" />
<form>
basically what I am suggesting is, do not use template tags unless absolute necessary like CSRF.
in this way, you can completely separate the design from the backend logic. you can have front end work indecently on the UI. the interface is the form fields, you have to supply all fields to the backend. like in this case 'email' && 'password' is required at backend

Function with arguments in a template. Django

In my template, I display a list of users a user follows. I would like the user to be able to delete one of the users he follows thanks to a button.
I have a function remove_relationship that deletes a relationship.
Here is the function in my models.py:
class UserProfile(models.Model):
(...)
def remove_relationship(self, person):
Relationship.objects.filter(
from_person=self,
to_person=person).delete()
return
I would like to pass this function into my template:
{% for user in following % }
<form method="post">
{% csrf_token %}
<input type="submit" value="delete" onclick="remove_relationship"/>
</form>
{%endfor%}
The thing is that I can't pass argument in my template. So how can I do so that each button deletes the relationship with the right user?
I saw an other question on this topic, abut it looks like it doesn't solve my problem (http://stackoverflow.com/questions/1333189/django-template-system-calling-a-function-inside-a-model)
Thank you for your help.
It looks as though you are confusing client-side code (JavaScript) with server-side (Django).
To get the relevant user ID submitted you could add an additional hidden field to the form:
{% for user in following % }
<form method="post" action="{% url views.remove_relationship %}">
{% csrf_token %}
<input type="hidden" name="user_id" value="{{ user.id }}">
<input type="submit" value="delete" />
</form>
{%endfor%}
Then create a remove_relationship view that does the deletion on the server side, based on the user id you'll now find in request.POST['user_id']

Customizing django-comments

So, I'm using django.contrib.comments. I've installed it OK but rather than the unwieldy default comment form, I'd like to use a custom form template that just shows a textarea and submit button.
The rationale behind this is that user only see the form if they area already authenticated, and I'd like the keep the form simple and pick up their username etc automatically.
I've implemented a custom form, but am getting an error when I try to submit it.
Here's what I have in my template for the page with the comment form (entry is the object passed from the view):
{% load comments %}
{% render_comment_form for entry %}
And here's my HTML in /templates/comments/form.html:
{% if user.is_authenticated %}
<p>Submit a comment:</p>
<form action="/comments/post/" method="post">
<textarea name="comment" id="id_comment" rows="2" style="width: 90%;"></textarea>
<input type="hidden" name="options" value="{{ options }}" />
<input type="hidden" name="target" value="{{ target }}" />
<input type="hidden" name="gonzo" value="{{ hash }}" />
<input type="hidden" name="next" value="{{ entry.get_absolute_url }}" />
<span style="float:right;"><input type="submit" name="post" value="Add"></span>
</form>
{% else %}
<p>Please log in to post a comment.</p>
{% endif %}
It renders okay initially, but when I try to submit the comment form, I get the following Django error:
Comment post not allowed (400)
Why: Missing content_type or object_pk field.
Can anyone help?
The comment model uses a generic foreign key to map to the object for which the comment was made such as a blog entry. These are required hidden fields included in the standard comment form.
From django.contrib.comments.models
...
class CommentSecurityForm(forms.Form):
"""
Handles the security aspects (anti-spoofing) for comment forms.
"""
content_type = forms.CharField(widget=forms.HiddenInput)
object_pk = forms.CharField(widget=forms.HiddenInput)
...
If you haven't changed the form class and only want to change the html template then you can include these fields by adding a for loop over all the hidden fields.
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
Fixed the problem by copying from Theju's app - in particular, see Joshua Works' comment on part 2.