Django only submitting csrf token in forms? - django

So, I have this in my template:
<form action="./validate_code/" method="POST">
{% if error %}
<p>Sorry, that wasn't right.</p>
{% endif %}
<label for="class_code">Your class code: </label>
<input type='text' id='class_code'/>
<input type="color" id="color"/>
{% csrf_token %}
<input type="submit" value="submit">
</form>
Which compiles to:
<form action="./validate_code/" method="POST">
<label for="class_code">Your class code: </label>
<input type='text' id='class_code'/>
<input type="color" id="color"/>
<input type='hidden' name='csrfmiddlewaretoken' value='tGA4jKF1pd1QFC6NSAM9eNFvZqss0r4m' />
<input type="submit" value="submit">
</form>
And when I click submit, firefox sends this parameter:
csrfmiddlewaretoken:"tGA4jKF1pd1QFC6NSAM9eNFvZqs60r4m"
That's it. No text, no color. I have no idea what's going on.

None of your fields have a name attribute, so the browser sends no data.
You should really be using Django's forms framework for this, though.

As mentioned above, you need to specify a "name" attribute in your input fields. You don't need to use Django forms, but if you are submitting the form normally, any fields you are expecting to be sent need to have a name.
<form action="./validate_code/" method="POST">
{% if error %}
<p>Sorry, that wasn't right.</p>
{% endif %}
<label for="class_code">Your class code: </label>
<input type="text" name="class_code" id="class_code">
<input type="color" name="color">
{% csrf_token %}
<button type="submit">Submit</button>
</form>

Related

How to save a form which contains a container div with sub-divs that have been dynamically added in django

I am working on a job portal system. I provide users the chance to edit their profiles by adding and removing job experiences. The issue is I don't know how to send that data to the view so that it can retrieve all the fields and store them in the database accordingly. By retrieving, I mean for each job experience, retrieve their corresponding sub fields
Here is my template file:
<!--JOB EXPERIENCE-->
<div class="job_experience">
<h5>Experience</h5>
<hr>
<!--FORM-->
<form action="#" id="save_job_experience_form" method="POST">
{% csrf_token %}
<div class="job_container">
{% for job in job_experience %}
<div class="exp">
<label>Organisation</label>
<input type="text" class="form-control" name="organisation
placeholder="Organisation" value="{% if job.organisation %}
{{job.organisation}}{% endif %}" required>
<label>Job Title</label>
<input type="text" name="job_title" class="form-control" value="{% if job.job_title
%}{{ job.job_title }}{% endif %}" placeholder="Job Title e.g Backend Developer"
required>
<button style="margin-left:15px;" type="button" class="btn btn-danger
remove_job_exp"><strong>Delete Job Experience</strong></button>
</div>
<hr>
{% endfor %}
</div>
<!--BUTTONS-->
<input type="submit"value="Save">
<input type="button" id="add_job_experience"value="Add one">
</form>
</div>
<script>
$(document).on('click', '#add_job_experience',function(e){
e.preventDefault();
$(".job_container").append(`<div class="exp">
<!--IT GOES ON AS ABOVE -->
$(document).on('click', 'button.remove_job_exp', function(e){
e.preventDefault();
$(this).closest('div.exp').remove();
});
You can post multiple inputs with the same name like so:
<input type="text" name="job[]" value="job1"/>
<input type="text" name="org[]" value="org1"/>
<input type="text" name="job[]" value="job2"/>
<input type="text" name="org[]" value="org2"/>
Then in django you can parse the POST data like so:
#require_POST #require POST method or check if request method is POST
def add_jobs(request):
jobs = request.POST.getlist('job[]')
orgs = request.POST.getlist('org[]')
...
Or use Django Formsets: https://docs.djangoproject.com/en/3.2/topics/forms/formsets/

Django: How can I render my formsets without having every single field in a <p> (or any other) element without losing the management form?

I'm rendering my model formset in the following way:
<form method="POST" class="note-form">
{{ formset.management_data }}
{% csrf_token %}
{{ formset.as_p}}
<input type="submit" value="Save">
</form>
However, this renders every single field in every form in a <p> element, which I don't want. It's unpacked like this:
<form method="POST" class="note-form">
<input type="hidden" name="csrfmiddlewaretoken"...>
<input type="hidden" name="form-TOTAL-FORMS"...>
<input type="hidden" name="form-INITIAL-FORMS"...>
<input type="hidden" name="form-MIN-NUM-FORMS"...>
<input type="hidden" name="form-MAX-NUM-FORMS"...>
<p>
<textarea ...></textarea>
</p>
<p>
<input ...>
</p>
<p>
<input ...>
</p>
<p>
<textarea ...></textarea>
</p>
...and so on...
</form>
Instead, I want something that would be rendered like this
<form method="POST" class="note-form">
<input type="hidden" name="csrfmiddlewaretoken"...>
<input type="hidden" name="form-TOTAL-FORMS"...>
<input type="hidden" name="form-INITIAL-FORMS"...>
<input type="hidden" name="form-MIN-NUM-FORMS"...>
<input type="hidden" name="form-MAX-NUM-FORMS"...>
<div ...>
<textarea ...></textarea>
<input ...>
<input ...>
</div>
<div ...>
<textarea ...></textarea>
<input ...>
<input ...>
</div>
....and so on....
That is, each single form in a div element. Now, I tried doing the following
<form method="POST" class="note-form">
{{ formset.management_data }}
{% csrf_token %}
{% for form in formset %}
<div>
{{ form }}
</div>
{% endfor %}
<input type="submit" value="Save">
</form>
This renders the formset the way I want it. The problem with this is that, when I do it, the management data disappears and I get the error 'ManagementForm data is missing or has been tampered with'.
I found something a bit similar in the documentation, but still, this is not working for me. What am I doing wrong?
Try:
<table>
{{ formset.as_table }}
</table>
Apparently, if the formset is not rendered with {{ formset.as_p }}, {{ formset.as_table }} or similar, the management data is not rendered automatically. It has to be rendered manually.
{{ formset.management_data }}
{% csrf_token %}
<div class="notes-pane">
{{ formset.management_form }}
{% for form in formset %}
<div>
{{ form }}
</div>
{% endfor %}
<input type="submit" value="Save">
</div>
</form>

Django: Trouble with logging user using Bootstrap login.html

I'm using Django 3.0.2 + Boostrap. I have created a registration/login.html page. The contents of this page are shown below.
The page renders correctly and most of it works OK. However, I am unable to login to my website through this page. I keep getting Your username and password did not match. Please try again. I can login to the admin website without any issues if I use the same username/password. I am not sure what is wrong with my login.html. Any ideas?
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password did not match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account does nohave access to this page. To proceed,please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1>
</div>
<form class="user" method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control form-control-user" id="exampleInputUserName" placeholder="Username">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="exampleInputPassword" placeholder="Password">
</div>
<input type="submit" class="btn btn-primary btn-user btn-block" value="Login">
<input type="hidden" name="next" value="{{ next }}">
</form>
<hr>
<div class="text-center">
<a class="small" href="forgot-password.html">Forgot Password?</a>
</div>
<div class="text-center">
<a class="small" href="register.html">Create an Account!</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Contents of views.py:
from django.contrib.auth import logout
def logout_view(request):
"""Log out user from the website."""
logout(request)
Your input types are missing the name attribute. As per the Mozilla docs:
A string specifying a name for the input control. This name is
submitted along with the control's value when the form data is
submitted.
So the name is submitted with the form. But what if there is no name attribute?
Same Documentation explains:
Consider the name a required attribute (even though it's not). If an
input has no name specified, or name is empty, the input's value is
not submitted with the form.
So your username and password are not sent to the backend.
You need to provide the name attributes to your input types.
<form class="user" method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control form-control-user" id="exampleInputUserName" placeholder="Username" `name="username"`>
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="exampleInputPassword" placeholder="Password" name="password">
</div>
<input type="submit" class="btn btn-primary btn-user btn-block" value="Login">
<input type="hidden" name="next" value="{{ next }}">
</form>
It is front-end issue, not particularly related to Django.

django model form with bootstrap doesn't work

I am making a website using django but I have a problem with my modelforms. This is my working form code in my html-file:
<form class="form-horizontal" role="form" method="post" action="">
<div class="form-group">
{% csrf_token %}
{{ form.as_p }}
</div>
<input type="submit" value="Inschrijven!" class="btn btn-primary" />
</form>
If i use this code, everything works fine, when I fill in the form and press send, I can see the information from my admin-page.
I now tried to style my form using bootstrap:
<form class="form-horizontal" role="form" method="post" action="">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label class="col-sm-4 control-label">{{ field.label }}</label>
<div class="col-sm-4">
<input type="text" class="form-control" placeholder="{{field.label}} ingeven">
</div>
</div>
{% endfor %}
<input type="submit" value="Inschrijven!" class="btn btn-primary">
</form>
Now I have a nice bootstrap layout but if I fill in the form, I can't see the information at my admin-page.
Does somebody know how I can fix this so I can keep the nice layout and still have my form to work?
When you output Django HTML form, you will notice that it creates input elements with the following ID and Name attributes of the element.
Eg
class MyForm...
name = ...
age = ...
HTML
<input type='text' id='id_name' name='name' ...
<input type='text' id='id_age' name='age'...
To fix your issue, in your HTML add the following attribute to the HTML input field you're generating
id="id_{{field.name}}" name="{{field.name}}"
Reasoning:
When the form is submitted, the browser will send form encoded data in the form of name=value pair, which then arrives in form of dict in request.POST and when fed into Django form, it pre fills the form by matching the Django form attribute name to POST values.

Django registration and password reset on one page

Is there way to create just one page for login and reset password?
I tried to create two forms page with following code in template:
<form action="" method="post" id="formLoginIndex">
{% csrf_token %}
<div id="elogin">
<p><label for="id_username">Login</label>
{{ form.username }}</p>
<p><label for="id_password">Пароль</label>
{{ form.password }}</p>
</div>
<p class="submit">
<button type="submit" class="enter">Enter</button>
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% else %}
<input type="hidden" name="next" value="/electricity/" />
{% endif %}
<button class="forgot" type="button" onclick="$('#forgotten').toggle('normal');">Forgot password?</button>
</p>
</form>
<div id="forgotten">
<form action="/reset/done/" method="post" id="formForgot">
{% csrf_token %}
<p>
<label for="id_username_forgot">Login</label>
<input id="id_username_forgot" type="text" name="username" maxlength="30" />
</p>
<p>
<label for="id_email">e-mail</label>
<input id="id_email" type="text" name="email" maxlength="40" />
</p>
<p class="submit">
<button class="remember" type="submit">Reset</button>
</p>
</form>
</div>
And urls :
url(r'^login/$', 'django.contrib.auth.views.login'),
url(r'^reset/done/$', 'django.contrib.auth.views.password_reset_done'),
However works only login feature. Reset doesn't work. Obviously is that I'm just doing smth wrong.
So should I load somehow views.password_reset into the same page or even rewrite django in auth views or there is another common solution?
The point is that you need a form to show the PasswordResetForm and it's action should be set to point to reset/
when this form is submitted via method POST, it's redirected to where the argument post_change_redirect points to, and there you can show the user that the password has been changed.
( In case the form evaluates to be correct , else, it would re-render the form with errors shown )
url(r'^reset/$', password_reset,
{'template_name':'your_template',
'post_change_redirect':'/reset/done/',
'extra_context':{'argument':'to tempate'}}, name='some_name'),
url(r'^reset/done/', password_reset_done,
{'template_name':'the template to show a success message',
'extra_context':{'message':'your password is changed successfully'}},),
looking at the defaults for this function ,It gives some cool info about how it works and its defaults if not given:
password_reset (request, is_admin_site=False,
template_name='registration/password_reset_form.html',
email_template_name='registration/password_reset_email.html',
subject_template_name='registration/password_reset_subject.txt',
password_reset_form=PasswordResetForm,
token_generator=default_token_generator,
post_reset_redirect=None,
from_email=None,
current_app=None,
extra_context=None)