I have tried to add a book in to the database using an HTML form. After the submission, the page redirect to a page where all the books are listed .Then whenever I refresh the page , the data is became duplicated. How do I resolve this problem?
urls.py
from django.urls import path
from . import views
app_name='library'
urlpatterns =[
path('', views.home, name='home'),
path('book/',views.book,name='book'),
path('book_details/<int:book_id>',views.book_details,name='book_details'),
path('book_edit/<int:book_id>',views.book_edit,name='book_edit'),
path('book_delete/<int:book_id>',views.book_delete,name='book_delete'),
path('update/<int:book_id>',views.update,name='update'),
path('author/',views.author_view,name='author_view'),
path('addbook/',views.add_book,name='add_book'),
path('books/',views.add_submit,name='add_submit'),
]
views.py
def add_submit(request):
if request.method =='POST':
title=request.POST.get('t_title')
print(title)
author_name=request.POST.get('a_author')
author, created=Author.objects.get_or_create(Name=author_name)
summary=request.POST.get('s_summary')
date=request.POST.get('d_date')
book=Book(Title=title,Author=author,Summary=summary,Published_date=date)
book.save()
books=Book.objects.all()
return render(request,'books.html',{'books':books})
Template file:
<form action="{% url 'library:add_submit' %}" method="POST">
{% csrf_token %}
<div class="form-outline mb-4">
<input type="text" id="bname" name="t_title" class="form-control" />
<label class="form-label" for="bname">Title</label>
</div>
<div class="form-outline mb-4">
<input type="text" id="bauthor" name="a_author" class="form-control" />
<label class="form-label" for="bauthor">Author</label>
</div>
<div class="form-outline mb-4">
<textarea rows="5" cols="33" id="bsummary" name="s_summary" class="form-control"></textarea>
<label class="form-label" for="bsummary">Summary</label>
</div>
<div class="form-outline mb-4">
<input type="date" placeholder="" id="pdate" name="d_date" class="form-control" />
<label class="form-label" for="pdate">Published_Date</label>
</div>
<!-- Submit button -->
<button type="submit" class="btn btn-primary btn-block">SUBMIT</button>
</form>
This is most common problem, the thing is that after dealing with POST data you should always return an HttpResponseRedirect, the tip is not specific to Django, but it's a good web practice in general so:
urls.py:
urlpatterns =[
...
path("success/", views.success, name="success"
]
views.py:
def add_submit(request):
if request.method =='POST':
title=request.POST.get('t_title')
print(title)
author_name=request.POST.get('a_author')
author, created=Author.objects.get_or_create(Name=author_name)
summary=request.POST.get('s_summary')
date=request.POST.get('d_date')
book=Book(Title=title,Author=author,Summary=summary,Published_date=date)
book.save()
return redirect("library:success")
else:
books=Book.objects.all()
return render(request,'books.html',{'books':books})
def success(request):
return render("success.html")
success.html
<h2> The form has been successfully submitted.</h2>
Go back to form
Related
I am currently learning Django,I connected my register FORM with my views.py, and wrote a little backend code, the problem, is that it links successfully with my .html file, and the POST elements are registering, but as I try to make a verification, (if POST_element < 10), it does nothing.
Edit: The Post elements are recognised by my backend, I test it out with a print(username) statement and it works fine.
Here is a part of my HTML Register FORM:
<div class="limiter">
<div class="container-login100" style="background:black;">
<div class="wrap-login100">
<form action="{% url 'register' %}" method="POST" class="login100-form validate-form">
{% csrf_token %}
<span class="login100-form-logo">
<i class="zmdi zmdi-landscape"></i>
</span>
<span class="login100-form-title p-b-34 p-t-27">
Register
</span>
<div class="wrap-input100 validate-input" data-validate = "Enter username">
<input class="input100" type="text" name="username" placeholder="Username">
<span class="focus-input100" data-placeholder=""></span>
</div>
Here is a part of my views.py that manages register:
def register(request):
if request.method=="POST":
username = request.POST["username"]
password = request.POST["pass"]
password_confirm = request.POST["pass-confirm"]
email = request.POST["mail"]
if len(username) < 7:
messages.error(request,"Username must be more than 10 char.") #Don't get any error
else:
messages.success(request,"Success")
return render(request, 'users/register.html')
Here is my urls.py:
urlpatterns = [
path('', views.register, name='register'),
path('login/', views.login, name='login')
]
An Excerpt from the django-doc about POST request.
You should always return an HttpResponseRedirect after successfully dealing with POST data. This tip isn’t specific to Django; it’s good web development practice in general.
You haven't return any response in POST request, and the messages framework whether any messages consists of error,success,etc. will send messages to next redirected page, so that's why you are not able to see the message, and your condition is working.
check the below code:
Html code:
<div class="limiter">
<div class="container-login100" style="background:black;">
<div class="wrap-login100">
<form class="login100-form validate-form" method='POST' action="{% url 'users:register' %}" >
{% csrf_token %}
<span class="login100-form-logo">
<i class="zmdi zmdi-landscape"></i>
</span>
<span class="login100-form-title p-b-34 p-t-27">
Register
</span>
<div class="wrap-input100 validate-input" data-validate = "Enter username">
<input class="input100" type="text" name="username" placeholder="Username" required>
<span class="focus-input100" data-placeholder=""></span>
</div>
<div class="wrap-input100 validate-input" data-validate="Enter password">
<input class="input100" type="password" name="pass" placeholder="Password" required>
<span class="focus-input100" data-placeholder=""></span>
</div>
<div class="wrap-input100 validate-input" data-validate="Confirm password">
<input class="input100" type="password" name="pass-confirm" placeholder="Confirm Password" required>
<span class="focus-input100" data-placeholder=""></span>
</div>
<div class="wrap-input100 validate-input" data-validate="Enter Email">
<input class="input100" type="email" name="mail" placeholder="E-Mail" required>
<span class="focus-input100" data-placeholder=""></span>
</div>
<div class="container-login100-form-btn">
<button class="login100-form-btn">
Register
</button>
</div>
<div class="text-center p-t-90">
<a class="txt1" href="login">
Already registered?
</a>
</div>
</form>
</div>
</div>
</div>
Set following style at the top of page in <style> tag, i.e. inline style:
<style>
.green{
color:green;
font-size:1.3rem;
}
.red{
color:red;
font-size:1.3rem;
}
</style>
urls.py
app_name='users'
urlpatterns = [
path('', views.register, name='register'),
path('login/', views.login, name='login')
]
Note: Giving app_name is a good practice,works like template namespacing while giving urls.
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.contrib import messages
from django.urls import reverse
def register(request):
if request.method == "POST":
username = request.POST["username"]
password = request.POST["pass"]
password_confirm = request.POST["pass-confirm"]
email = request.POST["mail"]
# Here everying exist.
print("UserName : ", username)
print('Email : ', email)
print('Password : ', password)
print('Password Confirm : ', password_confirm)
if len(username) < 7:
# Here error exist.
print('Username must be more than 10 char.')
messages.error(
request, "Username must be more than 10 char.", 'red')
return HttpResponseRedirect(reverse('users:register'))
else:
messages.success(request, "Success! form submitted.", 'green')
return HttpResponseRedirect(reverse('users:register'))
return render(request, 'users/register.html')
Note: You can also do password hashing through make_password which is from django.contrib.auth.hashers import make_password.
I can't render form username on the template. like I want to to render the form fields automatically which I defined in forms.py file but it's not working. here you go below for my detailed files
forms.py
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
views.py
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
My views
from .forms import CreateUserForm
Registration
def regPage(request):
form = CreateUserForm()
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
form.save()
context = {'form':form}
return render(request, 'web/car-finder-home.html')
html
<form class="needs-validation" method="POST" action="">
{% csrf_token %}
<div class="mb-4">
<label class="form-label text-light" for="signup-name">Username</label>
{{ form.username }}
</div>
<div class="mb-4">
<label class="form-label text-light" for="signup-email">Email address</label>
<input class="form-control form-control-light" type="email" id="signup-email" placeholder="Enter your email" required />
</div>
<div class="mb-4">
<label class="form-label text-light" for="signup-password">Password <span class="fs-sm opacity-50">min. 8 char</span></label>
<div class="password-toggle">
<input class="form-control form-control-light" type="password" id="signup-password" minlength="8" required />
<label class="password-toggle-btn" aria-label="Show/hide password"> <input class="password-toggle-check" type="checkbox" /><span class="password-toggle-indicator"></span> </label>
</div>
</div>
<div class="mb-4">
<label class="form-label text-light" for="signup-password-confirm">Confirm password</label>
<div class="password-toggle">
<input class="form-control form-control-light" type="password" id="signup-password-confirm" minlength="8" required />
<label class="password-toggle-btn" aria-label="Show/hide password"> <input class="password-toggle-check" type="checkbox" /><span class="password-toggle-indicator"></span> </label>
</div>
</div>
<div class="form-check form-check-light mb-4">
<input class="form-check-input" type="checkbox" id="agree-to-terms" required />
<label class="form-check-label" for="agree-to-terms">
<span class="opacity-70">By joining, I agree to the</span> Terms of use <span class="opacity-70">and</span> Privacy policy
</label>
</div>
<button class="btn btn-primary btn-lg w-100" type="submit">Sign up</button>
</form>
views.py
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
from .forms import CreateUserForm
def regPage(request):
form = CreateUserForm()
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
form.save()
# consider adding a redirect page here this is a good approach
else:
context = {'form':form}
return render(request, 'web/car-finder-home.html',context) # your forgot to add context
Now inside your template you can access the form...
I didn't add in core urls.py
from my_app_name import urls
urlpatterns = [
path('cars/', views.regPage, name="register"),
]
xD
I am doing authentication using crispy forms in Django. I would like to modify labels username and password in login view, but I can't find any solution to do it (I think that I have to create my own login form, but maybe it is possible to extend it).
urls.py
path('admin/', admin.site.urls),
path('register/', user_views.register, name='register'),
path('profile/', user_views.profile, name='profile'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
path('', include('blog.urls')),
]
login.html
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Login
{{ form|crispy}}
</legend>
</fieldset>
<div class="form-group">
<button type="submit" class="btn btn-outline-info">Login</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">Don't have an account? <a class="ml-2" href="{% url 'register' %}">Register</a> </small>
</div>
</div>
{% endblock content %}
I dont really understand what you're trying to achieve but if you're trying to modify the look of the fields you can do this in your forms.py file the fields you want to modify you can add bootstrap classes their for example in my login form I did this:
email = forms.EmailField(label='Email', max_length=50, widget=forms.EmailInput(attrs={"class":"form-control mb-3",'placeholder': 'Email'}))
password = forms.CharField(label='Password',widget= forms.PasswordInput(attrs={"class":"form-control mb-3",'placeholder': 'Password'}))
The Django way would be to create a forms.py like described in Haris Ahmad's answer but Johnson's answer is valid as well.
It is possible to create two inputs like so:
<input id="id_login" name="login" type="email" class="form-control">
<input id="id_password" name="password" type="password" class="form-control">
Full example:
<div class="content-section">
<form method="POST">{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
<!-- Username field -->
<label for="id_login">Username or email</label>
<input id="id_login" name="login" type="email" class="form-control">
<!-- Password field -->
<label for="id_password">Password</label>
<input id="id_password" name="password" type="password" class="form-control">
</legend>
</fieldset>
<div class="form-group">
<button type="submit" class="btn btn-outline-info">Login</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">Don't have an account?
<a class="ml-2" href="{% url 'register' %}">Register</a>
</small>
</div>
</div>
I don't quite understand your question but if you want more control over your input fields you should render raw html instead of form. You just have to ensure the field name of the input matched the name of the form field
<input name="username" type="text" .......>
I have a login modal in base.html. on clicking the login button modal gets open. I want that when the form has submitted the action='login' should call the login function of views.py but when I try to submit, it redirects the page to the login page which does not exist ('http://127.0.0.1:8000/login'). I want to know how can I call login function of views from modal, if I'm not wrong then action='' attribute calls the function and not the page. I tried removing the path of login from urls.py.
base.html
<div class="modal fade" id="modalLoginForm">
<div class="modal-dialog" role="document">
<div class="modal-content">
<!-- Default form login -->
<form class="text-center border border-light" action="login" method="post" autocomplete="off">
{% csrf_token %}
<!-- Email -->
<input type="text" name="username" class="form-control mb-4" placeholder="E-mail" required>
<!-- Password -->
<input type="password" name="password" class="form-control mb-4" placeholder="Password" required>
<div class="d-flex justify-content-around">
<div>
<!-- Remember me -->
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="defaultLoginFormRemember" name="remember_me">
<label class="custom-control-label" for="defaultLoginFormRemember">Remember me</label>
</div>
</div>
<div>
<!-- Forgot password -->
Forgot password?
</div>
</div>
<!-- Sign in button -->
<input class="btn btn-info btn-block my-3" type="submit" value="Sign in">
</form>
<!-- Default form login -->
</div>
</div>
</div>
views.py
def login(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect('/')
else:
messages.info(request, 'invalid credentials')
return redirect('index')
else:
return render(request, 'index.html')
app urls.py
urlpatterns = [
path('', views.login, name='login'),
path('register',views.register, name='register'),
path('logout', views.logout, name='logout')
]
project urls.py
urlpatterns = [
path('', include('camroid_app.urls')),
path('accounts/', include('accounts_app.urls')),
path('admin/', admin.site.urls),
]
how can i call login() of views from <form action='login'>
as it is raising error: The current path, login, didn't match any of these.
how can i call function of views directly from <form action='login'>
try:
action="{% url 'login' %}"
or
action="/"
do you know how to do this function? I used LOGIN_REDIRECT_URL but now I have two types of users and the two in different views how to redirect them to the corresponding view? Thanks in advance!
And I deal with this way in the view:
from django.contrib.auth.views import login
def my_login(request, user):
if request.user.is_superuser:
#your logic here
return HttpResponseRedirect('/solicitar/home/')
if request.user.is_active:
#your logic here
return redirect("/dashboard/")# or your url name
and url global:
urlpatterns = [
# Examples:
url(r'^solicitar/', include(urls, namespace="usuario")),
url(r'^admin/', include(admin.site.urls)),
url(r'^grappelli /',include('grappelli.urls')),
url(r'^grappelli /',include('grappelli.urls')),
url(r'^$', my_login, {'template_name':'login.html'}, name="login"),
url(r'^logout/', logout_then_login, name="logout"),
But I throw the error:
Page not found (404)
Request Method: GET
Request URL: http://sgi-hrr.herokuapp.com/accounts/profile
I should redirect myself to the 'home'.
my template login.html:
...
<img src="">
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="form-group">
<label for="username">Usuario:</label>
<input class="form-control" type="text" name="username"
required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="form-group">
<label for="username">Contraseña:</label>
<input class="form-control" type="password" name="password" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="form-group">
<input class="btn btn-primary" type="submit" value="Ingresar">
</div>
</div>
</div>
Help me please! Thanks in advance...
try it, it should work
from django.contrib.auth.views import login
from django.shortcuts import redirect
def my_login(request, user):
if request.user.is_superuser:
#your logic here
return redirect('/solicitar/home/')
if request.user.is_active:
#your logic here
return redirect("/dashboard/")
also add your default LOGIN_REDIRECT_URL in settings.py
LOGIN_REDIRECT_URL = /solicitar/home/