I had a tutorial in django with forms and I tried to do exactly what is taught , but I found that either my form in not sending the post method or django can't realize that the request sent is a POST request
here is my file named "register.html":
{% extends "blog/base.html" %}
{% block content %}
<div class="content-section">
<form role="form" method="post">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Join Today</legend>
{{ form.as_p }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">
Already Have An Account? <a class="ml-2" href="#">Sign In</a>
</small>
</div>
</div>
{% endblock content %}
and here the django side views.py:
from django.shortcuts import render , redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
def register (request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
messages.success(request, f'Account created for {username}!')
return redirect('blog-home')
else:
form = UserCreationForm()
return render(request, 'users/register.html' , {'form': form})
the result is when I click submit , the POST method is not working , I tried to pass a get request and it worked , so the problem only appears when I try to send the POST request , so where is problem ?
In the django's views.py or in the html file ?
Add action url to your form
<form role="form" action="/url/" method="post">
refer this
I agree with #c.grey's comment, If the form has errors, then the view will just return the form with form-data pre-filled and error messages associated with the fields and form (your errors might be not visible due to some CSS).
You can also try to see the execution path using a debugger like pdb or ipdb. for example
import ipdb; ipdb.set_trace()
from django.shortcuts import render , redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
def register (request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
username = form.cleaned_data.get('username')
messages.success(request, f'Account created for {username}!')
return redirect('blog-home')
else:
print("Request is not == POST")
return render(request, 'users/register.html' , {'form': form})
Related
I have hard time with such a easy thing (I guess).
My aim is to create two subpages with 2 different forms yet connected with the same user model:
/account/register.html - page only to manage registration (create user with login,email,password)
/account/questionnaire.html - page for UPDATING the same user information such as age,weight,height etc.
I've got 'POST' communicates in server log but nothing appears when I'm checking up django admin site.
models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
age = models.PositiveIntegerField(blank=False)
weight = models.PositiveIntegerField(blank=False)
height = models.PositiveIntegerField(blank=False)
forms.py
from django import forms
from django.core import validators
from django.contrib.auth.models import User
from account.models import UserProfile
class RegisterUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username','email','password')
class RegisterUserInfoForm(forms.ModelForm):
class Meta():
model = UserProfile
fields = ('age','weight','height')
views.py
from django.shortcuts import render
from account.forms import RegisterUserForm, RegisterUserInfoForm
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from django.contrib.auth.decorators import login_required
def register(request):
registered = False
if request.method == 'POST':
user_form = RegisterUserForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
else:
print(user_form.errors)
else:
user_form = RegisterUserForm()
return render(request,'account/register.html',{
'user_form':user_form,
'registered':registered,
})
#login_required
def questionnaire(request):
if request.method == 'POST':
profile_form = RegisterUserInfoForm(request.POST, instance=request.user)
if profile_form.is_valid():
profile_form.save()
else:
print(profile_form.errors)
else:
profile_form = RegisterUserInfoForm(instance=request.user)
return render(request,'account/questionnaire.html',{
'profile_form':profile_form,
})
register.html
{% extends 'base.html' %}
{% block body_block %}
<div class="container">
<h1>Register</h1>
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
<input type="submit" name="btn btn-primary" value="Save">
</form>
</div>
{% endblock %}
questionnaire.html
{% extends 'base.html' %}
{% block body_block %}
<div class="container">
<h1>questionnaire</h1>
<form method="post">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="" value="Save">
</form>
</div>
{% endblock %}
Your view doesn't receive a POST request because you didn't provide an action attribute to your form tag. So, your form passes your POST request nowhere. Try it like this:
<form action="" method="post">
{% csrf_token %}
{{ user_form.as_p }}
<input type="submit" name="btn btn-primary" value="Save">
</form>
Also, you should definitely check django's built-in generic views: CreateView and UpdateView. They serve exactly for such purposes and makes almost everything for you.
The user enters the data in the form. But the data entered in the form doesn't get displayed in the Database.
views.py
def add(request):
if request.method=='POST':
form=FilesCreate(request.POST)
if form.is_valid():
form.save()
return render(request,'plagiarism/page1.html',{'form':FilesCreate()})
def add2(request):
if request.method=='POST':
form2=FilesCreate2(request.POST)
if form2.is_valid():
form2.save()
return render(request,'plagiarism/page2.html',{'form':FilesCreate2})
models.py
from django.db import models
class File1(models.Model):
#user=models.ForeignKey(User)
firstfile=models.CharField(max_length=1000, default="")
#secondfile=models.CharField(max_length=1000)
def __str__(self):
return self.firstfile
plagiarism/page1.html
<h1>Enter your first file</h1>
<form action="file2/" method="post">
{% csrf_token %}
{% for field in form %}
{{field}}
<input type="submit" value="Submit file1"/>
{% endfor %}
</form>
plagiarism/page2.html (displays page after clicking submit in page 1)
<h1>Enter your second file</h1>
<form action="plagiarism/file2/result/" method="post">
{% csrf_token %}
{% for field in form %}
{{field}}
<input type="submit" value="Get Results"/>
{% endfor %}
</form>
{% block h1 %}
{% endblock %}
<body>
plagiarism/page3.html (displays page after clicking submit in page 2)
<h1> Here is your Result </h1>
<h2>
{{data}}
</h2>
</body>
forms.py
from django.forms import ModelForm
from django import forms
from plagiarism.models import File1,File2
class FilesCreate(ModelForm):
class Meta:
model=File1
exclude=()
widgets={'firstfile':forms.Textarea(attrs={'cols':50,'rows':100})}
example.py
from django.shortcuts import render
def getresult(request):
data=95.5
return render(request,'plagiarism/page3.html',{'data': data})
urls.py
from django.conf.urls import url
from . import views
from . import example3
urlpatterns=[
url(r'^$',views.add,name='add'),
url(r'file2/$',views.add2,name='add2'),
url(r'file2/result/$',example3.getresult,name='getresult')
]
You seem to want a kind of wizard, where you process a form and it redirects you to the next, but you're not doing the basics of form processing well. For simple form handling, you can do this:
urls.py
from django.conf.urls import url
from . import views
from . import example3
urlpatterns=[
url(r'^$',views.add,name='add'),
url(r'file2/result/$', example3.getresult, name='getresult')
]
In the template, you are calling file2 with the form's action, but you really want to call the same page, to process the form with the add view:
plagiarism/page1.html
<h1>Enter your first file</h1>
<form method="post">
{% csrf_token %}
{% for field in form %}
{{field}}
{% endfor %}
<input type="submit" value="Submit file1"/>
</form>
Note the missing action attribute in the <form> element.
When you visit the root of the website, the add view will be called with a GET request. When you submit the form, the same add view will be called, with a POST request, which will then be processed:
views.py
def add(request):
if request.method == 'POST':
form = FilesCreate(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('getresult'))
else:
form = FilesCreate()
return render(request,'plagiarism/page1.html',{'form': form})
Note the HttpResponseRedirect, which redirects to a new page on success, and the else, which creates an empty form for the first time you visit the page (i.e. request.method is not POST, it is GET). This way, if the form isn't valid, the last line will render it bound to the data that was submitted and display the errors.
This should get you the data into the database, which was your first goal. If you want to go to another form upon submission, you can redirect there (instead of the result page) and do the same as above in the view add2.
There used to be a Django Form Wizard, but you can see this project to do multi-step forms.
I am following the documentation of the Django Forms but I do not know why my form does not want to show up !
I am creating a form that will get an email en create invitation for user to sign in using this app :https://github.com/bee-keeper/django-invitations
My forms.py:
class InviteForm(forms.Form):
email1 = forms.EmailField(label='Email 1')
My Views.py:
from django.shortcuts import render
from django.views.generic import TemplateView
from .forms import InviteForm
class candidateIndex(TemplateView):
template_name= 'candidateIndex.html'
class HRIndex(TemplateView):
template_name= 'HRindex.html'
def create_invite(request):
if request.method == 'POST':
form = InviteForm(request.POST)
if form.is_valid:
email = form.cleaned_data['email1']
invite = Invitation.create('form.email1')
invite.send_invitation(request)
print("The mail was went")
else:
print("Your form is not valid")
else:
form = InviteForm()
return render(request, 'HRindex.html', {'form': form})
My HTML:
{% extends 'base.html' %}
{% block body %}
<div class="jumbotron">
<h1>Welcome to SoftScores.com</h1>
<h2>Team analytics platfom</h2>
<h3>Welcome to {{user.username}}, it is your Page</h3>
</div>
<div class="container">
<p>
<a class="btn btn-primary" data-toggle="collapse" href="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
Create a new team
</a>
</p>
<div class="collapse" id="collapseExample">
<div class="card card-body">
In order to create a new team please invite new members. A link will be sent to them in order to give the access to the application
</div>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</div>
</div>
urls.py:
from django.conf.urls import url
from website import views
app_name = 'website'
urlpatterns = [
url(r'^candidateIndex/$', views.candidateIndex.as_view(), name='candidate_index'),
url(r'^HRIndex/$', views.HRIndex.as_view(), name='HR_index'),
]
When it render the page I get only the button but the form does not seems to work
Do you habe any idea ?
You HR_index url is being handled by the HRIndex view, but this does not have any code to handle the form.
url(r'^HRIndex/$', views.HRIndex.as_view(), name='HR_index'),
Since a TemplateView is not really suited to handling a form, it would be better to modify the URL pattern to use the create_invite view instead:
url(r'^HRIndex/$', views.create_invite, name='HR_index'),
I am trying to implement the login field using django's authenticationForm.
the problem im having is that,because im trying to display two different forms inside one page (post_list) it seem to cause many errors.
one is for login field, and one is for the posting articles.
i also seem to have problem with duplicate forms as the two forms use the samename for the form which i do not know how to change.
also, there an error occurring when i try to post something using the post form.
to blatantly put, how do i make the login field visible?
i refer you to the working site : http://mtode.com( this is just a representation site, and do not contain login field part)
this is my views py which contains the definitions
from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404, redirect
from .forms import PostForm, AuthenticationForm
from .models import Post
from django.contrib.auth import authenticate, login
from django.contrib.auth import login
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.contrib.auth.decorators import login_required
def post_detail(request, id=None):
#instance = Post.objects.get(id=1)
instance = get_object_or_404(Post, id=id)
context = {
"title": instance.title,
"instance": instance,
}
return render(request, "post_detail.html", context)
def post_list(request):
if request.method == "POST":
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
login(request, form.get_user())
return HttpResponseRedirect('/post-list/')
else:
form = AuthenticationForm(request)
return TemplateResponse(request, 'login.html', {'form': form})
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
print (form.cleaned_data.get("title"))
instance.save()
# message success
messages.success(request, "Successfully Created")
return HttpResponseRedirect(instance.get())
#else:
#messages.error(request, "Not Successfully Created")
queryset = Post.objects.all()#.order_by("-timestamp")
context = {
"object_list": queryset,
"title": "List",
"form": form,
}
return render(request, "post_list.html", context)
#return HttpResponse("<h1>List</h1>")
def post_update(request, id=None):
instance = get_object_or_404(Post, id=id)
form = PostForm(request.POST or None, instance=instance)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
# message success
messages.success(request, "Saved")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"title": instance.title,
"instance": instance,
"form":form,
}
return render(request, "post_form.html", context)
def post_delete(request, id=None):
instance = get_object_or_404(Post, id=id)
instance.delete()
messages.success(request, "Successfully deleted")
return redirect("posts:list")
and this is the forms.py that contains the forms
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = [
"title",
"content"
]
from django.contrib.auth import authenticate
class AuthenticationForm(forms.Form):
username = forms.CharField(max_length=254)
password = forms.CharField(widget=forms.PasswordInput)
def clean(self):
username = self.cleaned_data['username']
password = self.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is None:
raise forms.ValidationError('invalid_login')
return self.cleaned_data
and this is the post_list.html
{% extends "base.html" %}
{% block content %}
<form method="post" action="">
{% csrf_token %}
Username: {{ form.username }} {{ form.username.errors }}<br>
Password: {{ form.password }} {{ form.password.errors }}<br>
{{ form.errors }}<br>
<input type="submit" value="login" />
</form>
<div class='two columns right mgr'>
<h1>Form</h1>
<form method='POST' action=''>{% csrf_token %}
{{ form.as_p }}
<input class="button-primary" type='submit' value='Create Post' />
</form>
</div>
<div class='four columns left'>
<h1>{{ title }}</h1>
{% for obj in object_list %}
<div class="row">
<div>
<a href='{{ obj.get_absolute_url }}'>
<div class="thumbnail">
<!--<img src="..." alt="...">!-->
<div class="caption">
<h3>{{ obj.title }}<small> {{ obj.timestamp|timesince }} ago</small></h3>
<p>{{ obj.content|linebreaks|truncatechars:120 }}</p>
<!-- <p>View </p>-->
</div>
</div></a>
</div>
<hr />
</div>
{% endfor %}
</div>
{% endblock content %}
Thank you.
When your page is initially displayed, request.method is GET. Therefore the post_list view is creating a PostForm instance and passing that into your template as the form element.
PostForm does not have username or password attributes, so those items are treated as empty strings and do not render at all.
If you want a template to render two forms, you need to pass them as separate names. You can't call them both "form".
After user logs in, user is able to submit a form. On click of submit button, data is being stored in DB, but how should I connect this information to the submitting user.
I would need the code as well as the structure of the new db
Kind of starting out in django.
Any help would be appreciated!!!
I have included user as foreign key in the CustomizeRequest model, but now how do i fill in this information?
Exact Scenario: After user log in, once he comes to contactUs.html, he submits a form which tells the number of travellers. This number is being stored in the DB. But now how do I connect each of these numbers to the submitted user?
models.py
class CustomizeRequest(models.Model):
user = models.ForeignKey(User)
travellers = models.CharField(max_length=2)
def __str__(self):
return self.travellers
contactUs.html
<form method="POST" class="form-horizontal">
{% csrf_token %}
<div class="btn-group" data-toggle="buttons">
{% for radio in crform.travellers %}
<label class="btn btn-default {% if radio.choice_label = '1' %}active{% endif %}" for="{{ radio.id_for_label }}">
{{ radio.choice_label }}
{{ radio.tag }}
</label>
{% endfor %}
</div>
<button type="submit" class="btn btn-default btn-block btn-warning">SUBMIT</button>
</form>
views.py
def contactUs(request):
if request.method=="POST":
form = CustomizeRequestForm(request.POST)
form.save()
else:
form = CustomizeRequestForm()
context_dict = {'form': form}
return render(request, 'tour/contactUs.html', context_dict)
Based on catavaran answer (with a check to see if the form is valid):
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
#login_required
def contactUs(request):
form = CustomizeRequestForm(data=request.POST or None)
if request.method == "POST":
if form.is_valid():
customize_request = form.save(commit=False)
customize_request.user = request.user
customize_request.save()
return redirect('.')
else:
pass # could add a notification here
context_dict = {'form': form}
return render(request, 'tour/contactUs.html', context_dict)
Logged user is available as request.user property. You can get the unsaved model instance using form.save(commit=False) trick, set the user field and then save the instance to database:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
#login_required
def contactUs(request):
if request.method == "POST":
form = CustomizeRequestForm(request.POST)
if form.is_valid():
customize_request = form.save(commit=False)
customize_request.user = request.user
customize_request.save()
return redirect('.')
else:
form = CustomizeRequestForm()
context_dict = {'form': form}
return render(request, 'tour/contactUs.html', context_dict)