Getting csrfmiddleware token in url - django

I am getting csrf token in the url after submitting my form like this.
http://127.0.0.1:8000/detail/?csrfmiddlewaretoken=lqvoeSG32IcodLTFksWEU1NPQ9XCmHybwmzMKEuPzxDN1e73B0JORpAGOcGGxsjH&symbol=FLWS
After making a GET request to view, the url is showing the csrf token in the url.
/views.py
def search(request):
if(request.method=='GET'):
form=searchform(request.GET)
if(form.is_valid()):
id=request.GET['symbol']
data=company.objects.filter(Symbol=id)
form=searchform()
return render(request, 'list-company.html',{"data":data,"form":form})
/urls.py
from django.contrib import admin
from django.urls import path
from csv2db.views import Company,search
urlpatterns = [
path('admin/', admin.site.urls),
path('company/',Company,name='company-details'),
path('detail/',search,name='search')
]
form in HTML file
{% block content %}
<form method="get" action="{% url 'search' %}">
{% csrf_token %}
{{ form.as_ul}}
<button type="Submit">Submit</button>
</form>

You are adding csrf_token template tag in the HTML file and form method is set to get. So data is appended as query parameters including csrf token.
So you can either change it to post method or remove the csrf_token template tag.

{% block content %}
<form method="POST" action="{% url 'search' %}">
{% csrf_token %}
{{ form.as_ul}}
<button type="Submit">Submit</button>
</form>
and change your view
def search(request):
form=searchform()
if(request.method=='POST'):
form=searchform(request.POST)
if(form.is_valid()):
id=request.GET['symbol']
data=company.objects.filter(Symbol=id)
form=searchform()
return render(request, 'list-company.html',{"data":data,"form":form})
return render(request, 'list-company.html',{"form":form})

Related

Why is Django product editing not working. Reverse for 'edit' not found?

I'm trying to edit a product (without using forms.py) but I get an error Reverse for 'edit' not found. 'edit' is not a valid view function or pattern name.
vievs.py
def edit(request, id):
if (request.method == 'POST'):
obj, update = Posts.objects.update_or_create(title=request.POST.get("title"))
obj.text=request.POST.get("text")
obj.date=request.POST.get("date")
obj.image=request.POST.get("image")
obj.save()
return render(request, 'edit.html')
html
<form action="{% url "blog:edit" %}" method="post">
{% for el in posts %}
{% csrf_token %}
<input type="text" placeholder="Название" name="title" value="{{ el.title }}"><br>
<textarea placeholder="Текст статьи" rows="8" cols="80" name="text"></textarea><br>
<input type="file" name="image"><br>
<button type="submit">Добавить статью</button>
{% endfor %}
</form>
You need to define the view in your blog app's urls.py file. Something like this:
urlpatterns = [
# ... other patterns
path('<int:id>/edit/',views.edit,name='edit'),
]

How to prevent redirect_to_login from targeting LOGIN_REDIRECT_URL

So in general when a user logs in, my app redirects him to dashboard-overview:
# settings.py
# Login and Logout target routes
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'dashboard-overview'
LOGOUT_REDIRECT_URL = '/'
However for a specific case I want the user to be redirected to 'calculator-page' using a helper function which doesn't work as the user is again redirected to the value of LOGIN_REDIRECT_URL.
# views.py
def render_calculator(request, slug):
"""
Renders the calculator page
"""
# Check for the user being authenticated
if not request.user.is_authenticated:
return redirect_to_login('calculator-page')
# routes to http://127.0.0.1:8000/login/?next=calculator-page which looks fine,
# but then it fails after login to re-route as specified and sends to
# 'dashboard-overview' again
else:
club_obj = Offer.objects.get(club__slug=slug)
# Create Context
context = {
'club_obj': club_obj,
}
return render(request, 'core/calculator.html', context)
# urls.py
from django.urls import path, include
from django.contrib.auth import views
from applications.user import views as user_views
urlpatterns = [
# Login View
path('login/', views.LoginView.as_view(template_name='user/login.html'), name="login"),
path('logout/', views.LogoutView.as_view(), name="logout"),
# Sign Up
path('signup/', user_views.signup, name='signup'),
]
# template user/login.html
{% extends 'user/user_frame.html' %}
{% load static %}
<!-- Styles -->
{% block styles %}
<link href="{% static 'css/user_frame.css' %}" rel="stylesheet" type="text/css">
{% endblock styles %}
{% block form %}
<div class="logo-container"><img src="{% static 'images/logo_negative_text.svg' %}" class="logo-image"></div>
<div class="form-container">
<!-- form headline -->
<h1 class="form-headline">Login to your Farena Account</h1>
<!-- form -->
<form class="form" method="post" action=".">
{% csrf_token %}
<div class="error-wrapper">
<div class="errors">{{ form.non_field_errors }}</div>
</div>
<div class="email-wrapper field-wrapper">
<div class="tag name-tag">{{ form.username.label }}*</div>
<div class="input">{{ form.username }}</div>
</div>
<div class="password-wrapper field-wrapper">
<div class="tag">{{ form.password.label }}*</div>
<div class="input">{{ form.password }}</div>
<div class="forgot-password">Forgot Password?</div>
</div>
<!-- submit button -->
<button class="login-button" type="submit">Log In</button>
</form>
</div>
<div class="account-info">No account yet? Sign Up!</div>
{% endblock form %}
The issue is with your template for the login view - you're missing the next form field that tells Django where to redirect the user after they have logged in. See the documentation for sample template code for this view.
Specifically, you need to add this inside your form:
<input type="hidden" name="next" value="{{ next }}">
That's missing right now which means Django will always just default to LOGIN_REDIRECT_URL.

Change how GET url is displayed

Summary: If I search 'apple', the url will be http://127.0.0.1:8000/search_results?csrfmiddlewaretoken=rlUwb5Ju3Xr585FarH5eAGQJtpog83hqW4wRysbsMWM6eiO3prcKRONY28N118gR&query=apple&button= and I just want to know if there is a way to change this to something cleaner like 127.0.0.1:8000/search_results/apple?
Here is my code:
urls.py
path('search_results', views.search_results, name = 'search_results'),
html:
<form action="{% url 'search_results' %}" method="GET">
{% csrf_token %}
<input name = 'query' type = 'text'/>
<button type="submit" name="button">Search</button>
</form>
and views.py:
def search_results(request):
query =request.GET.get('query')
return HttpResponse(query)
I had tried to change these 3 lines in their respective files:
`path('search_results/<str:query>')`, # thought this would achieve /search_results/apple url
<form action="{% url 'search_results' 'query' %}" method="GET">
def search_results(request, query):
but this did not work. Does anyone know how I can achieve this?
The GET parameters are encoded in the query string [wiki]. The query string is not part of the path. There is thus no way to encode this that way. But you can indeed make a "redirect view" that moves it to the path.
You can change the redirect to:
# app/views.py
from django.shortcuts import redirect
def search_redir(request):
query =request.GET.get('query')
return redirect('search_results', query=query)
def search_results(request, query):
# …
pass
In your urls.py, you then define two views: one that will "catch" the initial GET request with the querystring, and one where you move the query to the path:
# app/urls.py
from django.urls import path
urlpatterns = [
path('search_results/', views.search_redir, name='search_redir'),
path('search_results/<str:query>/', views.search_results, name='search_results'),
]
In your form however, you still use the redirect view. Note that since you perform a GET request you do not need to use the {% csrf_token %}:
<form action="{% url 'search_redir' %}" method="GET">
<input name="query" type ="text"/>
<button type="submit" name="button">Search</button>
</form>

How to render template after failed form validation?

urls.py:
urlpatterns = [
path('employee/add_employee/', views.add_employee, name='add-employee'),
path('employee/add_employee/add/', views.add_employee_action, name='add-employee-action'),
]
I have add-employee page and some forms to fill there.
views.py:
def add_employee(request):
personal_form = PersonalEmployeeForm()
history_form = EmployeeHistoryForm()
return render(
request,
'sections/add_employee.html',
context={
'personal_form': personal_form,
'history_form': history_form,
}
)
def add_employee_action(request):
if request.method == "POST":
personal_form = PersonalEmployeeForm(request.POST)
history_form = EmployeeHistoryForm(request.POST)
if personal_form.is_valid() and history_form.is_valid():
# here is some logic with models
return redirect('add-employee')
else:
personal_form = PersonalEmployeeForm()
history_form = EmployeeHistoryForm()
return render(
request,
'sections/add_employee.html',
context={
'personal_form': personal_form,
'history_form': history_form,
}
)
template:
<form id="a-submit-form" action="add/" method="POST">
{% csrf_token %}
<div class="column-wrapper">
<div class="column">
<div class="form-wrapper">
{% for field in personal_form.visible_fields %}
{% include "elements/forms/form_line.html" %}
<br>
{% endfor %}
</div>
</div>
<div class="column">
<div class="form-wrapper">
{% for field in history_form.visible_fields %}
{% include "elements/forms/form_line.html" %}
<br>
{% endfor %}
</div>
</div>
</div>
<div class="button-bar-wrapper">
<div class="button_bar">
<a class="a-button positive" id="submit">Добавить</a>
<a class="a-button" href="{% url 'employee' %}">Сотрудники</a>
<a class="a-button" href="{% url 'index' %}">На главуную</a>
</div>
</div>
</form>
Submitting by <a> element is tested and worked well with jQuery script.
The problem is after submitting invalid forms I have a page with blah-blah/employee/add_employee/add/ URL. And if I try to submit forms again I have a page with blah-blah/employee/add_employee/add/add/ URL, which is incorrect. How can I render the page with blah-blah/employee/add_employee/ URL and show all error messages?
This is likely because you have written a relative URL in the <form> tag of the sections/add_employee.html template. The template thus contains something like:
<form method="post" action="add/">
...
</form>
You can use a URL with the {% url … %} template tag [Django-doc]:
<form method="post" action="{% url 'add-employee-action' %}">
...
</form>
Furthermore one usually uses the same path to handle both the GET and the POST request. So in fact you might simply remove the 'add-employee' path.

Uploading and displaying an image in Django

I am currently learning Django. I am building a system that gets input from the user as image and throws back the damage level. I have the python files all caught up. But I am having difficulty doing the Django part.
How do I get an image as input from the user ?
And how will I throw back the result of the code that does the damage level prediction to the front end ?
Thanks in advance
To get images from user you can do as following. However getting data from request is not recommended way.
Views.py
from django.shortcuts import render, render_to_response
from django.core.files.storage import FileSystemStorage
def index(request):
if request.POST:
if request.method == 'POST' and request.FILES['image']:
uploaded_image = request.FILES['image']
fs = FileSystemStorage()
filename = fs.save(uploaded_image.name, uploaded_image)
uploaded_file_url = fs.url(filename)
code = get_code(uploaded_file_url)
return render_to_response("homepage.html", {"code": code})
else:
return render(request, "homepage.html")
Using this request.FILES['image'] we are getting a image from our form passed on post event.
In your template homepage.html
<form method="post" action="{% url 'code' %}" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="image" id="file-input" accept="image/x-png,image/jpeg,image/jpg"/>
<input type="submit" style="background: #0b0b0b" class="btn btn-secondary" value="Generate Caption"/>
<br><br>
<div style="background: #0b0b0b">
<a>Code for image is : {{ code }}</a>
</div>
</form>
{% url 'code' %} this will reverse the url by name as defined in urls.py. {% csrf_token %} is required for security reasons. enctype="multipart/form-data" is required to pass data like images, files etc. Input with name name="image" is what we are looking in request.FILES['image']. If you want change the name make your to change it everywhere.
And in your urls.py
from django.conf.urls import url
urlpatterns = [
url(r'^$', views.homepage, name='code'),
]
Also you can have look at Django forms for a better way.