receiving dropzone files in Django views - django

Could anyone help me to receive dropzone input in a function view in Django?
I wrote this code in my template for dropzone:
index.html:
<form method="post" action="{% url 'index' %}" enctype="multipart/form-data" class="dropzone" id="myDropzone" >
{% csrf_token %}
</form>
and for URLs.py:
url('^$', views.UI_index, name='index'),
and in views.py I receive the posted file by UI_index function:
def UI_index(request):
file_upload_message=''
if request.method=='post':
f = request.FILES['file']
file_upload_message='the file is received!'
return render(
request,
'cta_UI/index.html',
{'file_upload_message':file_upload_message},
)
in the index.html I receive the value of file_upload_message like {{file_upload_message}} but it doesn't seem to work properly, it seems that the condition of if request.method=='post' doesn't work, then how I can post the uploded file to a view? when the post metheod is exactly executed in dropzone?
Although it is not my real project it is the first step to receive a file in view...please help me by that.
Thanks.

request.method
you can try following code
def UI_index(request):
if request.method=='POST':
up_file = request.FILES['file']
if up_file:
destination = open('/tmp/' + up_file.name, 'wb+')
for chunk in up_file.chunks():
destination.write(chunk)
destination.close()
file_upload_message='the file is received!'
else:
file_upload_message='the file is missing!'
return render(request,'cta_UI/index.html',
{'file_upload_message':file_upload_message},)

Related

Testing Django view

I'm trying to test the following view
def generate_exercise_edl(request, ex_pk, unit_pk, *args, **kwargs):
ex_instance = Exercises.objects.get(id=ex_pk)
unit_instance = Units.objects.get(id=unit_pk)
unit_edl = UnitEdl.objects.filter(unit=unit_instance)
locations = Locations.objects.all()
unit_edl = list(unit_edl)
print(request)
print(request.POST)
print(request.user)
if request.method == "POST":
for item in unit_edl:
ExerciseEdl.objects.update_or_create(unit=unit_instance, exercise=ex_instance, equipment=item.equipment,
quantity=item.quantity, location=Locations.objects.get(location="Okinawa"))
print(request)
return redirect('exercise-equipment', ex_pk=ex_pk, unit_pk=unit_pk)
else:
messages.error(
request, f'Failed to add/update the {unit_instance.unit_name} edl for {ex_instance.exercise}.')
context = {
'ex_instance': ex_instance,
'unit_instance': unit_instance,
'unit_edl': unit_edl,
'locations': locations,
}
return render(request, 'exercise/exercise_edl.html', context)
This is my test code
def test_generate_edl(self):
unit_edl = UnitEdl.objects.filter(unit=unit.pk)
for edl in unit_edl:
ExerciseEdl.objects.update_or_create(
unit=unit,
exercise=ex,
equipment=edl.equipment,
quantity=edl.quantity,
location=loc
)
response = self.client.post(
f'/exercise/{ex.pk}/edl/{unit.pk}/convert/')
ex_edl = ExerciseEdl.objects.all().count()
self.assertEquals(ex_edl, 2)
self.assertEqual(response.status_code, 302)
This is the URL for the view
path('exercise/<int:ex_pk>/edl/<int:unit_pk>/convert', views.generate_exercise_edl, name='generate-edl'),
And the part of the template that calls my function
<form action="{% url 'generate-edl' ex_pk=ex_instance.id unit_pk=unit_instance.id %}" method="post">
{% csrf_token %}
<input class="btn btn-primary btn-sm mt-2" type="submit" value="Generate EDL">
</form>
My test returns 404, not 302, but the function on the site works, and redirects you.
f'/exercise/{ex.pk}/edl/{unit.pk}/convert/' isn't mapped to any template, it's just the url for the function. In the past my tests have returned a status code of 404 when I wrote the post data incorrectly.
print(request.POST) returns:
<QueryDict: {'csrfmiddlewaretoken':
['ZYT0dgMZqqgmCo2OufdI9B0hIJ5k5qPKcxnkReWPZy0iY9McaBO7MHENjYLzH66O']}>
Which makes sense because I'm not sending any post data, just the csrf token.
What I want to know is, am I on the right track with using 'response = self.client.post(
f'/exercise/{ex.pk}/edl/{unit.pk}/convert/')'?
With my other tests I include the post data in a dictionary along with the URL, but this function doesn't use any, so I just ran a similar function.
Is there a better way to test this? Should I just refactor?
You need to use reverse to build your URL rather than hard coding it. Since you hard coded it, it is getting a 404 since the URL the test tried to post to is incorrect.
I don't know the app_name in your URLs file, you will need to add that to the reverse. For example if it was excercise it would be exercise:generate-edl.
from django.urls import reverse
response = self.client.post(reverse(
'<app_name>:generate-edl',
kwargs={
ex_pk: ex.pk,
unit_pk: unit.pk,
}
))

What is the correct way of setting the Action attribute in a Django form

I have an html form in a Django system and I cannot find the correct way to implement the Action attribute in the form
html
<form action="stages" method="post">
urls.py
urlpatterns = [
path('<str:partner_pk>/stages/', views.Stages.as_view(), name="stages"),
]
views.py
class Stages(View):
"""CBV for setting stages."""
url = 'duo/stages.html'
def get(self, request, partner_pk):
app.context['partner_pk'] = partner_pk
return render(request, self.url, app.context)
def post(self, request, partner_pk):
"""Render the POST request."""
stages_selected = app.update_stages(request)
if app.context['use_stages'] and not stages_selected:
messages.error(request, 'You have not selected any stages.')
return render(request, f'{partner_pk}', app.context)
else:
return HttpResponseRedirect(reverse(f'duo/{partner_pk}/'))
The error I get on clicking submit is:
RuntimeError at /duo/2/stages/stages
You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set...
I have tried various other urls in action but the all give an error message
[EDIT 200200828]
The APPEND_SLASH message is misleading. It is just the message that I get with the html
<form action="stages" method="post">
If I change the html to
<form action={% url 'stages' partner_pk %} method="post">
or
<form action='?' method="post">
I get the message
NoReverseMatch at /duo/2/stages/'
You haven't set APPEND_SLASH option so all of your routes should have / afterwards but still it wouldn't work as you are appending relative path (notice stages doubling in URL)
Considering you are posting on same route you could omit action attribute
<form method="post">
or use something like (as HTML5 standard does not allow empty action)
<form action='?' method="post">
additionally you could use full path something like this
<form action="{% url 'stages' partner_pk %}" method="post">
The problem in this case was the reverse(url)
I change the post method in views.py to
def post(self, request, partner_pk):
"""Render the POST request."""
stages_selected = app.update_stages(request)
if app.context['use_stages'] and not stages_selected:
messages.error(request, 'You have not selected any stages.')
return render(request, f'{partner_pk}', app.context)
else:
return HttpResponseRedirect(f'/duo/{partner_pk}')
and it works

Django : downloading a file (pdf version or odt version) through radio buttons

I trying to propose to the users of my site to download a document in either pdf or odt version through radio buttons. How can I get and use the value of the radio button chosen by the user to serve the appropriate file. So far, I can only serve one at a time.
My current work:
models.py
class File(models.Model):
name = models.CharField(max_length=200)
pdf_version = models.FileField()
odt_version = models.FileField()
def __str__(self):
'''String name represents class File'''
return self.name
urls.py
path('files_page/', views.files_page, name='files_page'),
path('download_file/<int:file_id>/', views.download_file, name='download_file'),
views.py
def files_page(request):
files = File.objects.all()
context = {'files':files}
return render (request, 'walk/files_page.html', context)
def download_file(request, file_id):
#No post request; do nothing
if request.method != 'POST':
pass
else:
#fetch the file to download
#file = File.objects.get(id=file_id)
response = FileResponse(open('/home/me/Desktop/super/media_cdn/tog.pdf', 'rb'))
response['Content-Disposition'] = 'attachment; filename="tog.pdf"'
return response
template
{%block content%}
{%for file in files %}
<p>{{file.name}}</p>
<p>{{file.pdf_version}}</p>
<p>{{file.csv_version}}</p>
<form action="{%url 'walk:download_file' file.id%}" method="POST">
{%csrf_token%}
<input type="radio" name="format" value="pdf" checked> pdf
<input type="radio" name="format" value="csv"> csv
<button name="submit">download</button>
</form>
{%endfor%}
{%endblock content%}
Let's start with using forms. Yes, you use django forms in django instead re-implementing everything yourself.
Create forms.py:
from django import forms
FILE_FORMAT_CHOICES = [("csv", "Download PDF"), ("csv", "Download CSV")]
class FileFormatForm(forms.Form):
file_format = forms.ChoiceField(choices=FILE_FORMAT_CHOICES, widget=forms.RadioSelect())
Inside of the template used by files_page (just let django render the fields, don't do it yourself):
<form action="{%url 'walk:download_file' file.id%}" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="Download">
</form>
And finally adjust the views.py:
def files_page(request):
...
context = {
'files': files,
'form': FileFormatForm() # empty / without POST
}
...
def download_file(request, file_id):
assert request.method == 'POST', "users should only come here with POST now"
form = FileFormatForm(request.POST) # populate from POST
if form.data['file_format'] == 'pdf':
return "return PDF file response here"
else:
return "return CSV file response here"
Note: you don't use tab in Python. Use 4x whitespaces instead.
Another Note: Class Based Views to further reduce the amount of boilerplate.

django, views direct to a another html page

I am using Django for develop a website. The website is intended to use to search information stored in a MySQL database.
This is the current basic flow of the web site.
1) index.html - this has a form to select an option
2) according the option, users will redirect to search.html (include a form)
3) once the user provides the criteria, the result will be displayed in reply.html
In my views.py , I have two functions.
from django.shortcuts import render
from website.models import WebsiteRepository
from .forms import SearchForm
from .forms import SelectTypeForm
def Search(request):
if request.method == 'POST':
#do something
return render(request, 'reply.html', {'env_dict':env_dict})
else:
#do something
return render(request, 'search.html', context = context)
def index(request):
if request.method =='POST':
#do something
return render(request, 'search.html', context = context)
else:
#do something
return render(request, 'index.html', context= context)
When I go to index.html page, I can select a option and it will direct me to search.html. After, I fill the form there and submit, it wont give me the reply.html page.
I have a feeling that, I could make this work by changing urls.py.
from django.urls import path
from website import views
urlpatterns = [
path('', views.index, name='index'),
#path('search/', view.Search, name ='Search')
]
I tried to google it. But its too much details and Iam kind of lost.
Do any of you guys know how to achieve this?
Thanks
search.html
{% extends "base_generic.html" %}
{% block content %}
<h3>Welcome to search information Repository</h3>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
{% endblock %}
index.html
{% block content %}
<h3>Welcome to information Repository</h3>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
just for clarify things more, ill add the forms.py too
from django import forms
from .models import WebsiteRepository
class SearchForm(forms.Form):
websiterepository = WebsiteRepository
env_indicators = websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
indicator = forms.ChoiceField(choices=env_indicators,label = 'Indicator' )
OPTIONS = (('2000','2000'),('2001','2001'),('2002','2002'), ('2003','2003'),('0000','0000'),)
year = forms.ChoiceField(choices=OPTIONS)
class SelectTypeForm(forms.Form):
OPTIONS = (('1', 'Envirnmental Indicators'),('2','Economic Indicators'),('3','Social Indicators'),)
types = forms.ChoiceField(choices=OPTIONS)
Your code is wrong on many points.
First thing first: for a search, you want a GET request, not a POST (POST is for updating the server's state - adding or updating your database mostly). This is the semantically correct method (since you want to GET data), and it will allow a user to bookmark the url.
Second point: you don't want to submit the search form to the index view but to the search view. No need for redirects etc, just use the {% url %} templatetag to fill the action attribute of your form (you of course need to have a 'Search' url in your urls.py):
<form method="get" action="{% url 'Search' %}">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
if you want to have this form on more than one page (which is often the case for search forms), use an inclusion tag tha will take care of creating an unbound SearchForm and render the template fragment.
Then in your search view, you only want GET requests, and do not use two different templates, this will only lead to useless duplication.
def Search(request):
form = SearchForm(request.GET)
# use the form's data - if any - to get search results
# and put those results (even if empty) in you context
return render(request, 'reply.html', {'env_dict':env_dict})
And finally, your search form is totally broken:
class SearchForm(forms.Form):
# this is totally useless
websiterepository = WebsiteRepository
# this will only be evaluated once at process startup, so you will
# get stale data in production - and probably different data
# per process, in a totally unpredictable way.
# You need to either put this in the form's __init__ or wrap it
# in a callable and pass this callable
env_indicators = websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
indicator = forms.ChoiceField(choices=env_indicators,label = 'Indicator' )
# are you going to manually add a new year choice every year ???
OPTIONS = (('2000','2000'),('2001','2001'),('2002','2002'), ('2003','2003'),('0000','0000'),)
year = forms.ChoiceField(choices=OPTIONS)
For the "indicators" ChoiceField you want something like:
def get_indicators_choices():
return Websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
class SearchForm(forms.Form):
# IMPORTANT : we are NOT calling the function here, just
# passing it (python functions are objects) to the field, which
# will call it everytime the form is instanciated, so you don't
# have stale data
indicator = forms.ChoiceField(
choices=get_indicator_choices,
label='Indicator')
As a last note: be consistent with your namings (ie why name one view in all lower (index) and capitalize the other (Search) ? Whichever convention you choose (I strongly suggest respecting pep8 here), at least stick to it for the whole project.
The problem is that code is not redirecting to /search, instead rendering search.html after post from index.html.
Try doing like-
views.py-
#your code
def index(request):
#do something
if request.method == 'POST':
return redirect('Search')
else:
#render index.html
def search(request):
#do something
if request.method == 'POST':
#render reply.html
else:
#render search.html
Another way to achieve this is if you specify action in your form so that form posts on /search.
search.html
<form method="post" action="/search">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>

how to use variable data to use in template tag in Django template

In urls.py file
from articles.views import home
urlpatterns = patterns('',
url(r'^home/$',home.as_view(),name='home'),
)
In views.py file
class home(TemplateView):
template_name='article.html'
def get(self, request):
form = Homeform()
return render(request,self.template_name, {'form':form})
def post(self,request):
file_path = '/u/vinay/checking.py'
args={'file_path':file_path}
return render(request,self.template_name, args)
In article.html file
{% load static %}
<html>
<body>
Download plan</button>
<p>{{ file_path }} </p>
</body>
</html>
But i'm getting no file as output from GUI.
As i'm creating download link for that file in file_path location.So how do i render text from views to article.html
You dont neeed {{}} signs inside template tag. Try this:
"{% static file_path %}"
Check django docs for details.
Please refer to the documentation for template tags:
href="{% static file_path %}"
Ninja'ed..
Also, your view function is all messed up, I'm suprised it displays anything at all:
def vin(request):
return render(request,'article.html', {'file_path':'xyz.py'})
Try this:
class home(TemplateView):
template_name='article.html'
def get_context_data(self,*args,**kwargs):
context = super().get_context_data(*args,**kwargs)
context['file_path'] = '/u/vinay/checking.py'
return context
# END OF VIEW --- no get or post method, let the generic view handle that.