Uploading and displaying an image in Django - 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.

Related

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>

Getting csrfmiddleware token in url

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})

Proper way to handle multiple Django forms in one page with two views?

I've struggled with this problem for the last two days and could use some help. The home page for my Django 1.6 application will include two forms, one that a user can use to sign in to the site and one they can use to sign up (create a login) for the site:
# templates/home/home_page.html
<div class="sign-in-form">
<form action="{% url 'apps.home.views.sign_in' %}" method="post">
{% csrf_token %}
{{ sign_in_form.as_p }}
{% if next %}
<input type="hidden" name="next" value="{{ next }}">
{% else %}
<input type="hidden" name="next" value="{% url 'view-members' %}">
{% endif %}
<input type="submit" value="Sign in">
</form>
</div>
<div class="sign-up-form">
<fieldset>
<legend>Sign up</legend>
<form action="{% url 'apps.home.views.sign_up' %}" method="post">
{% csrf_token %}
{{ sign_up_form.as_p}}
<p><input type="submit" value="Sign up" /></p>
</form>
</fieldset>
</div>
If the user submits, the sign_in form, they'll be taken to a page where they can view other site members. If they submit the sign_up form, they'll be taken to a second signup page where they'll create a user profile, etc.
Originally, I was going to use the technique shown in this question and use one view to handle the homepage. However, I decided to try to use two views because I'm using the Django's actual login view (django.contrib.auth.views.login) so that I can add code to it to detect the user's device (phone, tablet, or computer), and merging that view with my sign_up view would create a very long and complicated view to maintain. I'd prefer to keep the views for both forms separate.
Here's the home page and sign_in views:
# apps/home/views:
def home_page(request, template):
sign_in_form = SignInAuthenticationForm()
sign_up_form = CreateAccountForm()
return render(request, template, {"sign_in_form": sign_in_form,
"sign_up_form": sign_up_form})
#sensitive_post_parameters()
#csrf_protect
#never_cache
def sign_in(request,
template='home_page.html',
redirect_field_name=REDIRECT_FIELD_NAME,
# authentication_form=AuthenticationForm,
authentication_form=SignInAuthenticationForm,
current_app=None, extra_context=None):
# Do device detection here...
# django.contrib.auth.views code goes here...
return response
The signup view will just be your typical, function-based view for processing a form as described in the Django documentation.
What I'm struggling with is my URLconf files. Here's my main and "home" URLconf files:
# conf/urls.py
urlpatterns = patterns('',
url(r'^$', include('apps.home.urls')),
# Other url patterns...
)
# apps/home/urls.py
urlpatterns = patterns('apps.home.views',
url(r'^$',
'home_page',
{'template': 'home/home_page.html'},
name='home-page'),
url(r'^sign_in/$',
'sign_in',
{'template': 'home/home_page.html'},
name='sign-in'),
url(r'^sign_up/$',
'sign_up',
{'template': 'home/home_page.html'},
name='sign-up'),
)
The problem is that I get this error during template rendering:
NoReverseMatch at /
Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']
Request Method: GET
Request URL: http://localhost:8000/
Django Version: 1.6.2
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']
Exception Location: /Users/smith/venv/swing/lib/python2.7/site-packages/django/core/urlresolvers.py in _reverse_with_prefix, line 429
Python Executable: /Users/smith/venv/swing/bin/python
Python Version: 2.7.5
Python Path:
['/Users/smith/Dropbox/www/swing',
'/Users/smith/venv/swing/lib/python2.7/site-packages/wurfl_cloud-1.0.1-py2.7.egg',
'/Users/smith/venv/swing/lib/python27.zip',
'/Users/smith/venv/swing/lib/python2.7',
'/Users/smith/venv/swing/lib/python2.7/plat-darwin',
'/Users/smith/venv/swing/lib/python2.7/plat-mac',
'/Users/smith/venv/swing/lib/python2.7/plat-mac/lib-scriptpackages',
'/Users/smith/venv/swing/Extras/lib/python',
'/Users/smith/venv/swing/lib/python2.7/lib-tk',
'/Users/smith/venv/swing/lib/python2.7/lib-old',
'/Users/smith/venv/swing/lib/python2.7/lib-dynload',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/Users/smith/venv/swing/lib/python2.7/site-packages']
At first I started to think that maybe it's telling me that it can's find the correct URL pattern in my home/urls.py file because the URL signature in my form is incorrect. Maybe I needed to do this to match the arguments in the sign_in view:
<form action="{% url 'apps.home.views.sign_in' 'home/home_page.html' %}" method="post">
But I'm already showing the template name in the home URLconf. And I don't think I need to pass the other view arguments in the form action (e.g. redirect_field_name) because their optional. In any case, adding this argument to the form action didn't fix it.
One of the things that confuses me is how to set the first url argument. I've set them to r'^sign_in/$' and r'^sign_up/$' because if I set them both to r'^$', the page will render properly but when I submit either form, it justs posts back to the home page. You can see this will happen by doing a "view source" on the page. It shows each form's action will be "/". On the other hand, the way I have it now seems incorrect to me because the site won't actually have a "/sign_in/" and "/sign_up/" URL since both forms are on the home page. Also, is there going to be a problem in which if the user submits one for or the other improperly, errors for both forms will be rendered on the page?
The Django documentation, to the best of my knowledge, doesn't really describe a standard approach for doing what I'm trying to do. It describes how to render multiple versions of the same form. Can anyone tell me what I'm doing wrong?
Thanks.
Your form names are 'sign_in_form' and 'sign_up_form', but in your html you wrote them 'form.as_p' instead of 'sign_in_form.as_p' and 'sign_up_form.as_p' this is the first bug a saw in your code.
The real problem is in your urls configuration. In your main urls.py you have
url(r'^$', include('apps.home.urls')),
Other ...
Though you will not be able to get to localhost:8000/sign_in/ because initially it does not satisfy to ^$ .
Try to change it by
url(r'', include('apps.home.urls')),
and put it to the end of urls.py.
i test this see if this what you want:
view.py
def loginUser(request,**Kargs):
LoginFormSet = formset_factory(LoginForm)
SignFormSet = formset_factory(SignForm)
if request.method == 'POST':
login_formset = LoginFormSet(request.POST, prefix='login')
sign_formset = SignFormSet(request.POST ,prefix='sign')
if login_formset.is_valid():
#do somthing
elif sign_formset.is_valid():
#do somthing
return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})
else:
login_formset = LoginFormSet(prefix='login')
sign_formset = SignFormSet(prefix='sign')
return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})
page.html:
<form action="{% url 'loginUser' %}" method="post">
{% csrf_token %}
{{ login_formset.management_form }}
{% for form in login_formset %}
{{ form }}
{% endfor %}
{{ sign_formset.management_form }}
{% for form in sign_formset %}
{{ form }}
{% endfor %}

django - middleware issue

I want to put a login form everywhere on my website, after following a few SO answers I decide to write my own middleware like this:
class LoginFormMiddleware(object):
'''
Put a login form in everypage of the website
'''
def process_request(self, request):
# if the top login form has been posted
if request.method == 'POST':
if 'logout_submit' in request.POST:
# log the user out
from django.contrib.auth import logout
logout(request)
form = LoginForm()
elif 'login_submit' in request.POST:
# validate the form
form = LoginForm(data=request.POST)
if form.is_valid():
# log the user in
from django.contrib.auth import login
login(request, form.get_user())
else:
form = LoginForm(request)
else:
form = LoginForm(request)
# attach the form to the request so it can be accessed
# within the templates
request.login_form = form
in my settings.py, I have:
import django.conf.global_settings as DEFAULT_SETTINGS
...
MIDDLEWARE_CLASSES = DEFAULT_SETTINGS.MIDDLEWARE_CLASSES + (
'base.mymiddleware.LoginFormMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.request',
)
The form, in base.html to be accesed from everywhere, looks like this:
{% if user.is_authenticated %}
<div class="login_box">
<form action="/myapp/logout/" method="post">{% csrf_token %}
<div class="col2"><a>{{ user.username }}</a></div>
<div class="col3"><input type="submit" value="Logout" name="logout_submit"/></div>
</form>
</div>
{% else %}
<form action="." method="post">
{% csrf_token %}
<div class="login_box">
<div class="error_box">
{% if request.login_form.errors %}
Incorrect User/Password
{% endif %}
</div>
<div class="col00"> <h4>{{ request.login_form.username.label_tag }}</h3></div>
<div class="col11">{{ request.login_form.username }}</div>
<div class="col22"><h4>{{ request.login_form.password.label_tag }}</h3></div>
<div class="col33">{{ request.login_form.password }}</div>
<div class="col44"><input type="submit" value="Login" name="login_submit"/></div>
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
</div>
</form>
{% endif %}
Login works normally but, after doing it, each time I make a GET request user.is_authenticated seems to return false cause what I see is an empty LoginForm instead of the logout form.
I dont know if the problem is in my middleware (when request.method != 'POST' it returns form = LoginForm(request)) or it is something I am missing in my settings, or maybe using middleware for this was not a great idea...
I can't believe you have seen any SO answers that advocate putting this sort of logic in the middleware. (If you have, post the link so that I can downvote them.)
This really, really, really isn't the place to do this sort of thing. Write a specific view and set the action parameter of the login form to that view.
However, I suspect your underlying issue is that you're not using RequestContext to render the other views, so the user object is not passed to the template.
Your implementation doesn't make much sense. A login form with action attribute is "." is wrong and will lead to conflicts.
You should have a login view, not a login middleware. The action attribute of the login form should be the reversed url of your login view.
In your login form, you should specify a next hidden input for example:
<input name="next" type="hidden" value="{{ request.POST.next|default:request.path }}" />
Following that, it can be in your base template or anywhere in the website.
This is also valid for logout.

Another CRSF token error while uploading file in django

I'm trying to upload a csv file in my view. I included csrf token however I'm directly taking 403 error when I try to upload a file. Here is my view and template:
MY FORM HTML
<div class="file-boxes">
<form enctype="multipart/form-data" action="" encoding="multipart/form-data" id="upload-csv" method="post">
{% csrf_token %}
{{form.csv}}
<!-- <input class="input-file" id="fileInput" type="file" size="14" name="csv_upload" onchange="this.form.submit()"> -->
</form>
</div>
MY FORM
class DeliveryDataForm(forms.Form):
csv = forms.FileField(widget=forms.ClearableFileInput(attrs={'size:':14,'onchange':'this.form.submit()'}))
MY VIEW
def upload_data(request):
...
form = DeliveryDataForm()
if request.method == "POST":
import pdb
pdb.stack_trace()
form = DeliveryDataForm(request.POST, request.FILES)
return HttpResponse('asd')
return render_to_response(template,context)
I know there are some missing parts in the view but the strange thing is, it never enters the if part. Any idea ?
from django.shortcuts import render
# ...
# return render_to_response(template,context)
return render(request,'index.html',context)