Django form submission & CSRF (403 Forbidden) - python

Upon providing valid data and submitting a form, I get the following: Forbidden (CSRF cookie not set.): /membership/success/. I have a {% csrf_token %} in my template and my settings.py middleware is configured for CSRF.
#urls.py
from django.contrib import admin
from django.urls import path, include
from membership import views as ms_views
membership_patterns = ([
path("", ms_views.RegistrationPage.as_view(), name="register"),
path("success/", ms_views.SuccessPage.as_view(), name="success")
], 'membership')
urlpatterns = [
path('admin/', admin.site.urls),
path('membership/', include(membership_patterns, namespace="new_members"))
]
# membership/views.py
from django.shortcuts import render
from django.template.loader import get_template
from django.views import View
from django.http import HttpResponse, HttpResponseRedirect
from membership.forms import RegisterForm
from django.urls import reverse
# Create your views here.
class RegistrationPage(View):
def get(self, request):
register_page = get_template('membership/signup.html')
register_form = RegisterForm()
return HttpResponse(register_page.render({'form' : register_form}))
def post(self, request):
submitted_form = RegisterForm(request.POST)
if submitted_form.is_valid():
return HttpResponseRedirect(reverse('membership:success'))
return HttpResponse(reverse('membership:register'))
class SuccessPage(View):
def get(self, request):
return HttpResponse("Success")
# signup.html
{% extends 'index.html' %}
{% block content %}
<form action="{% url 'membership:success' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
{% endblock %}
Once the form is submitted and valid, I'm expecting a 302 to occur. Like I said though I get 403 forbidden.

Since your success page has no logic, you can choose to exempt CSRF token for that.
Import the following module
from django.views.decorators.csrf import csrf_exempt
and put #csrf_exempt at the start of function
#csrf_exempt
def get(self, request):
return HttpResponse("Success")
Refer to https://docs.djangoproject.com/en/2.2/ref/csrf/
However, it is better to include {% csrf_token %} for each template you use to ensure consistent passing around of CSRF token

Related

Django POST request redirects to empty url after submitting form

I have a login form with POST method and when I submit the login data, it goes straight to the empty url and doesn't execute the login method in views.py. Ideally, after I submit the form in www.url.com/login via submit button, it should return a HttpResponse but instead, it takes me to www.url.com/
I am new to Django, I'd appreciate it if you could look into it. Thanks!
home.html
<center><h1>Welcome to my website</h1>
<form method='POST'> {% csrf_token %}
{{ form }}
<button type='submit' class='btn btn-default'>Submit</button>
</form>
</center>
urls.py
from django.contrib import admin
from django.urls import path
from .views import home, login
urlpatterns = [
path('', home),
path('login/', login),
path('admin/', admin.site.urls),
]
forms.py
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={"class":"form-control", "placeholder":"Your username"}))
password = forms.CharField(widget=forms.PasswordInput(attrs={"class":"form-control", "placeholder":"Your password"}))
views.py
from django.contrib.auth import authenticate, login
from django.http import HttpResponse
from django.shortcuts import render
from .forms import LoginForm
def home(request):
context={
"form": "Test"
}
return render(request, "home.html", context)
def login(request):
login_form = LoginForm(request.POST or None)
context={
"form": login_form
}
if login_form.is_valid():
username = login_form.cleaned_data.get('username')
password = login_form.cleaned_data.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
#request.user.is_authenticated()
login(request, user)
return HttpResponse("You are now logged in")
else:
return HttpResponse('Error')
return render(request, "home.html", context)
First, you should set an attribute action in the form which set a url to send.
Second, a url value in action must be clear. It's not a matter of Django but HTML.
I'd like to recommend you to use absolute path. If you use relative path, a slash string would be added whenever you send a request.
<form action="/login/" method='POST'>
{% csrf_token %}
{{ form }}
<button type='submit' class='btn btn-default'>Submit</button>
</form>
This is because your form doesn't contain action, i.e. where should the POST call be made with the user credentials.
Try following change in home.html:
<center><h1>Welcome to my website</h1>
<form action="" method='POST'> {% csrf_token %}
{{ form }}
<button type='submit' class='btn btn-default'>Submit</button>
</form>
</center>
Following the answers before, it would be a good practice to use named patterns instead of fixed urls.
# urls
...
path('login/', login, name='login'),
...
# template
<form action="{% url 'login' %}" method='POST'>
So if you change for example
login/
for
accounts/login/
You don't have to change the template as well.
urlpatterns = [
re_path('^$', home_page),
re_path('^admin/', admin.site.urls),
re_path('^register/$', register_page, name='register'),
re_path('^login/$', login_page, name='login'),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
I solved this by adding ^$to the beginning and end of the patterns.

Django save() method does not insert data to my Mysql database

I have tried to entered data to Mysql database using Django. The user enters the required data through addSubscriber.html page to save in the database but the data entered is not saved in the database. Whenever I check the Mysql table (in this case 'Subscribers' table), the table is empty. Should I install mysql-connecter or not?
Here are my files:
views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.views import generic
from .models import Subscribers
from .forms import addSubsForm
#login_required
def dashboard(request):
user = request.user
context = {'user': user}
template = 'dashboard.html'
return render(request, template, context)
#login_required
def addSubscriber(request):
template = 'addSubscriber.html'
if request.method == 'POST':
form = addSubsForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
area = form.cleaned_data['area']
phoneNumber = form.cleaned_data['phoneNumber']
installationCost = form.cleaned_data['installationCost']
billNumber = form.cleaned_data['billNumber']
print name
Subs = Subscribers.objects.create(name=name, area=area, phoneNumber=phoneNumber, installationCost=installationCost, billNumber=billNumber)
Subs.save()
return redirect('report')
else:
form = addSubsForm()
return render(request, template, {'form': form})
#login_required
def report(request):
context = locals()
template = 'report.html'
return render(request, template, context)
models.py
from __future__ import unicode_literals
from django.db import models
class Subscribers(models.Model):
name = models.CharField(max_length=120)
area = models.CharField(max_length=30)
phoneNumber = models.CharField(max_length=10)
installationCost = models.CharField(max_length=10)
billNumber = models.CharField(max_length=100, unique=True)
addSubscriber.html
{%extends 'base.html'%}
{% load staticfiles %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col-xs-7">
{% if form %}
<br>
<form class="POST" action="." method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" value="submit form" class="btn btn-primary"/>
</form>
{% endif %}
</div>
</div>
{% endblock %}
urls.py
from dashboard import views as dashboard_views
from profiles import views as profiles_views
from django.conf import settings
from django.conf.urls import url, include
from django.conf.urls.static import static
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', profiles_views.home, name='homepage'),
url(r'^contact/$', profiles_views.contact, name='contact'),
url(r'^dashboard/$', dashboard_views.dashboard, name='dashboard'),
url(r'^dashboard/addSubscriber/$', dashboard_views.addSubscriber, name='addSubscriber'),
url(r'^dashboard/userDetail/$', dashboard_views.userDetail, name='userDetail'),
url(r'^dashboard/report/$', dashboard_views.report, name='report'),
url(r'^account/', include('allauth.urls')),
]
# this statement says that: if in the settings file, DEBUG is true than use this static URL
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Since you are using two databases, for saving entities you should specify which database to save by specifying
Subs.save(using='db2')
According to Django documentation:
If you don’t specify using, the save() method will save into the
default database allocated by the routers.
well you dont need all this extra things in the view as you are using form and why use create and also save??
just try this inside the form.is_valid
if form.is_valid():
f = form.save(commit=False)
f.save(using='db2')
return redirect('report')

How can I display a user profile using Django?

I am new to django and I am currently trying to build a website that allows users to sign in and view other users profiles. So far I have managed to let users sign in but I can't work out how to view other peoples profiles.
Each profile uses the users username to create a url for their profile. Currently if I sign in as one user and change the URL to another users profile URL, it still displays the current users profile. I want something similar to pinterest where any person whether they are signed in or not can view peoples profiles.
Any help would be appreciated!
View
from django.http import HttpResponse
from django.shortcuts import render
from howdidu.forms import UserProfileForm
from howdidu.models import UserProfile
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User
def index(request):
context_dict = {'boldmessage': "I am bold font from the context"}
return render(request, 'howdidu/index.html', context_dict)
#user profile form
#login_required
def register_profile(request):
profile = UserProfile.objects.get(user=request.user)
if request.method == 'POST':
form = UserProfileForm(request.POST, request.FILES, instance=profile)
if form.is_valid():
form.save()
return index(request)
else:
print form.errors
else:
form = UserProfileForm()
return render(request, 'howdidu/register_profile.html', {'form': form})
#profile page using user name as url
#login_required
def profile_page(request, username):
user = get_object_or_404(User, username=username)
return render(request, 'howdidu/profile.html', {'profile_user': user})
project url
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf import settings
from registration.backends.simple.views import RegistrationView
class MyRegistrationView(RegistrationView): #redirects to home page after registration
def get_success_url(self,request, user):
return '/register_profile'
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'howdidu_project.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'', include('howdidu.urls')),
url(r'^accounts/register/$', MyRegistrationView.as_view(), name='registration_register'), #redirects to home page after registration
(r'^accounts/', include('registration.backends.simple.urls')),
url(r'^(?P<username>\w+)/', include('howdidu.urls')), #do i need this?
)
# media
if settings.DEBUG:
urlpatterns += patterns(
'django.views.static',
(r'^media/(?P<path>.*)',
'serve',
{'document_root': settings.MEDIA_ROOT}), )
app url
from django.conf.urls import patterns, url
from howdidu import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^register_profile/$', views.register_profile, name='register_profile'),
url(r'^(?P<username>\w+)/$', views.profile_page, name='user_profile'),
)
template
{% extends 'howdidu/base.html' %}
{% load staticfiles %}
{% block title %}{{ user.username }}{% endblock %}
{% block body_block %}
{% if user.is_authenticated %}
<h1>{{ user.username }} welcome to your profile page</h1>
<img src="{{ user.userprofile.profile_picture.url }}" width = "150" height = "150" />
<h2>{{ user.userprofile.first_name }}</h2>
<h2>{{ user.userprofile.second_name }}</h2>
<h2>{{ user.userprofile.user_country }}</h2>
{% endif %}
{% endblock %}
Register urls of your app in the configuration folder project_name/urls.py :
E.g :
from django.conf.urls import include, url
from django.contrib import admin
from django.conf import settings
urlpatterns = [
url(r'^user/', include('<app_name>.urls')),
url(r'^admin/', include(admin.site.urls)),
]
Add a new route in your <app_name>/urls.py.
E.g :
from . import views
urlpatterns = [
url(r'profile/(?P<username>[a-zA-Z0-9]+)$', views.get_user_profile),
]
Add a view in <app_name>/views.py that take username (username of the user) to retrieve its information and send them into a template
E.g :
from django.shortcuts import render
def get_user_profile(request, username):
user = User.objects.get(username=username)
return render(request, '<app_name>/user_profile.html', {"user":user})
Create a template file in <app_name>/templates/<app_name>/user_profile.htmlto display user object :
{{ user.username }}
{{ user.email }}
{{ user.first_name }}
{{ user.last_name }}
Replace <app_name> by the name of your app and it should be good.

Django login app at suburl, url redirection does not work properly

I have my page deployed at http://example.com. I also have my django application deployed at http://example.com/djangoapp.
I'm using Apache 2.2 with this configuration (/etc/apache2/apache2.conf): WSGIPythonPath /home/brian/djangoprojects/djangoapp.
I also added the line WSGIScriptAlias /djangoapp /home/brian/djangoprojects/djangoapp/djangoapp/wsgi.py to the default Apache Virtual Host file and it works really nice.
However, in my application I'm using the auth module to register and login users, and have some problems with it. Sometimes I got redirected to the main page, http://example.com/, sometimes to http://example.com/register instead of http://example.com/djangoapp/register.
Changes I made in my project:
Edited settings.py and added:
LOGIN_URL = '/djangoapp/accounts/login/'
USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = '/djangoapp'
SUB_SITE = "/djangoapp"
My urls.py file looks like this:
from django.conf.urls import include, url
from django.contrib import admin
from djangoapp import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'django.contrib.auth.views.login'),
url(r'^logout/$', views.logout_page),
url(r'^accounts/login/$', 'django.contrib.auth.views.login'), # If user is not login it will redirect to login page
url(r'^register/$', views.register),
url(r'^register/success/$', views.register_success),
url(r'^home/$', views.home),
]
And here's my views.py file:
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.template import RequestContext
from djangoapp.forms import RegistrationForm
#csrf_protect
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response(
'registration/register.html',
variables,
)
def register_success(request):
return render_to_response(
'registration/success.html',
)
def logout_page(request):
logout(request)
return HttpResponseRedirect('/')
#login_required
def home(request):
return render_to_response(
'home.html',
{'user': request.user}
)
This is the production server and it's available online. I tried to use a work-around, but with no effect. I simply changed links on page and added djangoapp at the beginning, for instance:
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block head %}Login{% endblock %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action=".">{% csrf_token %}
<table border="0">
<tr><th><label for="id_username">Username:</label></th><td>{{ form.username }}</td></tr>
<tr><th><label for="id_password">Password:</label></th><td>{{ form.password }}</td></tr>
</table>
<input type="submit" value="Login" />
<input type="hidden" name="next" value="/home" />
</form>
Register
{% endblock %}
And I tried to change Register to Register but I'm sure there's got to be a smarter solution. Any advice?
You need to use the {% url %} tag and the reverse function consistently. So:
Register
and
return HttpResponseRedirect(reverse('register_success'))
For this to work you also need to give your URL patterns names:
url(r'^register/$', views.register, name="register"),
url(r'^register/success/$', views.register_success, name="register_success"),
Aso, as I said in the comment, you do not need to set FORCE_SCRIPT_NAME yourself.

Problems with logging in/out standart django user using class-based views

I am trying to create simple application that allows just login existing user and logout if logged in.
views.py
from django.views.generic.edit import FormView
from django.views.generic import DetailView
from django.contrib.auth import logout
from django.contrib.auth.models import User
from django.contrib.auth.forms import AuthenticationForm
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect
class UserDetailView( DetailView ):
model = User
template_name = "main/user_detail.html"
class UserLoginView( FormView ):
form_class = AuthenticationForm
success_url = reverse_lazy("UserDetails")
template_name = "main/user_form.html"
def logout_view(request):
logout(request)
return HttpResponseRedirect('/login/')
urls.py
from django.conf.urls import patterns, include, url
from main import views
urlpatterns = patterns('',),
url( r'users/(?P<pk>\d+)/', views.UserDetailView.as_view(), name="UserDetails"),
url( r"logout/", views.logout_view, name="UserLogOut" ),
url( r"login/", views.UserLoginView.as_view(), name="UserLogIn" ),
)
user_form.html
{% if user.is_authenticated %}
Logout
{{ user.username }}
{% else %}
<form method='post'> {% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type='submit' value='Submit'>
</form>
{% endif %}
I don't know why, but server returns this error
Request Method: POST
Request URL: http://0.0.0.0:9000/login/
Django Version: 1.6.5
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'UserDetails' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
What's wrong?
UPD
I've tried this dirty hack success_url = reverse_lazy("Main:UserDetails", kwargs={ 'pk':1 } ) just to check that it's working. I've also added
{% if user.is_authenticated %}
Hooray!
{% else %}
What the hell???
{% endif %}
to the user_detail.html and for some reason got What the hell??? instead of Hooray!
Why authentication form doesn't actually authenticates user?
I think the problem is in this statement
success_url = reverse_lazy("UserDetails")
You need to provide user pk to reverse_lazy args, because URL is in form "users/user_id/".
So it's impossible to find out correct success URL.
In this line in your urlconf
url( r'users/(?P<pk>\d+)/', views.UserDetailView.as_view(), name="UserDetails"),
you are defining the url for UserDetails as 'something/users/pk'. But then you are not supplying a pk argument to that url. That's why your error says that the reverse was not found, because it tries to find a pattern which has no arguments.
There are several ways to fix your error, but I think the best solution would be to make the pk argument optional, like this:
url( r'users(?:/(?P<pk>\d+))?/', views.UserDetailView.as_view(), name="UserDetails"),
Hope this helps.

Categories

Resources