Django: passing variable from view.py to html with render - django

I am new to Django and I have the following problem
With views.py I render a page called 'results_links.html' located in application templates directory which has an 'include' statement toward another page 'MAPE_history.csv.html' located in 'upload' directory (which is also defined in settings.py as template directory). I want to dynamically pass the file to be used in 'included' statement from views.py. For the test I use same file: MAPE_history.csv.html
The problem I have is that I receive a 'template not existing'error from include statement. If I remove the statement of I replace the 'content' variable with the file name, I do not receive a problem.
Here is the code:
### views.py
from django.shortcuts import render
from django.http import HttpResponse
import os
from formupload import Best_model_forecast_v11
# Create your views here.
def home(request):
return render(request, 'index.html', {'what':'Django File Upload'})
def upload(request):
if request.method == 'POST':
handle_uploaded_file(request.FILES['file'], str(request.FILES['file']))
MAPE_file = 'MAPE_'+str(request.FILES['file'])+'.html'
return render(request,'result_links.html',{'content':MAPE_file})
elif request.method == 'GET':
return render(request,'result_links.html',{'content':'MAPE_history.csv.html'})
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'upload/MAPE_history.csv; filename="MAPE_history.csv"'
return response
return HttpResponse("Failed")
def handle_uploaded_file(file, filename):
if not os.path.exists('upload/'):
os.mkdir('upload/')
if not os.path.exists('forecast/'):
os.mkdir('forecast/')
with open('upload/' + filename, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
#print(Best_model_forecast_v11.main('upload/' + filename))
return Best_model_forecast_v11.main('upload/' + filename)
### result_links.html
<html>
<head>
<title>Rezultate</title>
<IMG SRC="logo.jpg" ALT="" WIDTH=100 HEIGHT=100>
</head>
forecast
{% block content %}
{% include 'logo.html' %}
{% include '{content}' %} # 'template not existing' error is coming from this statement!
<table>
<tr>
<td>
<form action="{{ request.build_absolute_uri }}" method="GET" enctype="multipart/form-data">
<input type="file" name="{content}"/>
<br />
<input type="submit" value="Rezultate" />
</form>
</td>
</tr>
</table>
<a href='{{ MEDIA_URL }}{{ content.relative_path }}'>{{content}}</a>
{% endblock %}
</html>
### settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates','d:/florian/django/mysite/upload/'),
'd:/florian/django/mysite/upload/'
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
### error
TemplateDoesNotExist at /upload/
{content}
Request Method: POST
Request URL: http://localhost:8000/upload/
Django Version: 1.11.7
Exception Type: TemplateDoesNotExist
Exception Value:
{content}
Exception Location: C:\Users\lored\Envs\simpleform\lib\site-packages\django\template\engine.py in find_template, line 148
Python Executable: C:\Users\lored\Envs\simpleform\Scripts\python.exe
Python Version: 3.5.0
Python Path:
['D:\\FLORIAN\\Django\\mysite',
'C:\\Users\\lored\\Envs\\simpleform\\Scripts\\python35.zip',
'C:\\Users\\lored\\Envs\\simpleform\\DLLs',
'C:\\Users\\lored\\Envs\\simpleform\\lib',
'C:\\Users\\lored\\Envs\\simpleform\\Scripts',
'c:\\python35\\Lib',
'c:\\python35\\DLLs',
'C:\\Users\\lored\\Envs\\simpleform',
'C:\\Users\\lored\\Envs\\simpleform\\lib\\site-packages']
Server time: Tue, 28 Nov 2017 18:27:27 +0000
Template-loader postmortem
Django tried loading these templates, in this order:
Using engine django:
django.template.loaders.filesystem.Loader: d:\florian\django\mysite\upload\{content} (Source does not exist)
django.template.loaders.filesystem.Loader: d:\florian\django\mysite\upload\{content} (Source does not exist)
django.template.loaders.app_directories.Loader: C:\Users\lored\Envs\simpleform\lib\site-packages\django\contrib\admin\templates\{content} (Source does not exist)
django.template.loaders.app_directories.Loader: C:\Users\lored\Envs\simpleform\lib\site-packages\django\contrib\auth\templates\{content} (Source does not exist)
django.template.loaders.app_directories.Loader: D:\FLORIAN\Django\mysite\formupload\templates\{content} (Source does not exist)
templates directory
enter image description here

The template name can either be a variable or a hard-coded (quoted) string, in either single or double quotes.
Try using {% include content %}

Accessing variables in Django like this requires double braces; change your {content} line to {{ content }}.
As an aside, check your "elif request.method == 'GET':" code, as the second return will never be reached.

Why are you using if elif try this one
def upload(request):
if request.method == 'POST':
handle_uploaded_file(request.FILES['file'], str(request.FILES['file']))
MAPE_file = 'MAPE_'+str(request.FILES['file'])+'.html'
return render(request,'result_links.html',{'content':MAPE_file})
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'upload/MAPE_history.csv; filename="MAPE_history.csv"'
return render(request,'result_links.html',{'content':'MAPE_history.csv.html'})

Related

Django & Jinja2 templates using {{ url() }}

I am trying to figure out how to pass my user_id within my html using jinja's {{ url() }}, using urls that don't need any id like /dashboard/ work fine but I need to pass an id to this- example: /user/3 . I have tried the following with no success:
{{ url('detail') }}
{{ url('detail', user_id=User.id) }}
{{ url('detail', User.id) }}
Here's part of my views and html:
views.py
urlpatterns = [
path('dashboard/', dashboard, name='dashboard'),
path('user/<int:user_id>/', detail, name='detail'),
]
dashboard.html
{% for User in all_users %}
{{ url('detail') }}
{% endfor %}
Any help on this would be appreciated, thanks
I found a solution:
{% for User in all_users %}
{{ url('detail', args=[User.id] )}}
{% endfor %}
This also works:
{% url 'detail' user.id %}
Then, in views.py, your corresponding function should receive user_id as an argument (internally user.id becomes user_id).
Django now has official backend support for Jinja2 - I'm guessing you were using django-jinja which provides an implementation of the url function but it's fairly straightforward to integrate Django and Jinja now without adding any additional dependencies (besides Jinja2).
First, configure your TEMPLATES in your settings file and add a dictionary entry with the jinja2 backend:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'APP_DIRS': True,
'OPTIONS': {
'extensions': [<custom extensions if any>]
'environment': 'yourapp.jinja2.environment',
...
},
},
...
]
The key part of this is the environment setting. The examples suggest creating a jinja2.py file in your app directory and defining an environment function there that you'll set to a function that returns a Jinja2 Environment, e.g.,
# example yourapp/jinja2.py
from django.conf import settings
from django.urls import reverse
from django.templatetags.static import static
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': static,
'url': reverse,
'settings': settings,
...
})
return env
Here we are binding Python functions (and Django things) to be made available in our Jinja2 environment, so now static in a jinja template can be called static(...) and invoke the Django static function defined in django.templatetags.static, and url is bound to the Django reverse function so url('detail', args=[user.id]) should work. If you prefer a signature like {{ url('detail', pk=123) }} without generating an invalid arguments error you can define your own function:
def jinja_url(viewname, *args, **kwargs):
return reverse(viewname, args=args, kwargs=kwargs)
and bind 'url': jinja_url in your TEMPLATES settings instead.
It's also important to note that Django looks for your jinja templates in a jinja2 directory under your app dir, not the templates directory.

Django 2.0 throws AttributeError: ''Image' object has no attribute 'replace'"

When trying to set an html image to my static path + image path in Django 2.0, the django development server displays the following error:
Error during template rendering
In template /Users/arikanevsky/webappgit/ari/templates/ari/software.html, error at line 5
'Image' object has no attribute 'replace'
The Image class from models.py:
class Image(models.Model):
"""This class contains a reference to the ImageField.
It is part of a base of models comprising the webapp.
"""
uplpath = '%Y/%m/%d'
dfltpath = 'page_images/Y/M/D/no_img.jpg'
image = models.ImageField(upload_to=uplpath, default=dfltpath)
def __str__(self):
"""Return human readable string of self.image."""
return self.image.name
The urlpatterns from urls.py:
urlpatterns = [
path('', views.index, name='index'),
path('<int:page_id>/bio/', views.bio, name='bio'),
path('<int:page_id>/software/', views.software, name='software'),
path('<int:page_id>/publications/',
views.publications, name='publications'),
path('<int:page_id>/career/', views.career, name='career'),
path('<int:page_id>/education/', views.education, name='education'),
]
The index method from views.py:
def index(request):
page_list = get_list_or_404(Page.objects.all())
return render(request, 'ari/index.html', {'page_list': page_list})
The index.html file (it is used as named):
{% if page_list %}
<ul>
{% for page in page_list %}
<p>My bio page</p>
<p>My career page</p>
<p>My software page</p>
<p>My publication page</p>.
{% endfor %}
</ul>
{% else %}
<p>No pages are available :(</p>
{% endif %}
The software method from views.py:
def software(request, page_id):
software_page = get_object_or_404(Page, pk=page_id)
return render(request, 'ari/software.html', {'software_page': software_page})
The software.html file:
{% load static %}
<img src = "{% static software_page.image %}" alt = "Profile Picture"/>
The app directory structure is the following:
(I believe we can ignore the .ipynb and pycache dirs)
|-akanev
| |-__pycache__
|-ari
| |-.ipynb_checkpoints
| |-__pycache__
| |-migrations
| | |-__pycache__
| |-templates
| | |-ari
| | | |-page_images
The relevant environment dir paths defined in settings.py:
MEDIA_ROOT: '/Users/arikanevsky/webappgit/ari/templates/ari/page_images'
MEDIA_URL: ''
BASE_DIR: '/Users/arikanevsky/webappgit'
STATICFILES_DIRS: []
STATIC_ROOT: None
STATIC_URL: '/page_images/'
TEMPLATES:
[{'APP_DIRS': True,
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'OPTIONS': {'context_processors': ['django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages']}}]
The img src line in the software.html file throws the error:
Exception Type: AttributeError at /ari/4/software/
Exception Value: 'Image' object has no attribute 'replace'
Would appreciate any and all clues to as what this mysterious error may be!
Thanks :)
You are using the static template tag wrong. It should be used for static files that you want to use on your pages. For example linking to a stylesheet, javascript or images that aren't user uploaded.
See here for more information:
https://docs.djangoproject.com/en/2.0/howto/static-files/
You are trying to get the picture from an uploaded file in your models -
probably done by a user upload (or done in a way that isn't "static"). This is handle via the media url and media root settings. See here:
https://docs.djangoproject.com/en/2.0/topics/files/
The correct way to get the image would be:
<img src = "{{ software_page.image.url }}" alt = "Profile Picture"/>
Best regards,
Andréas

Switch language in jinja template

I'm migrating a multi lingual Django application from Django's template engine to Jinja2. In the templates I currently switch the active language on a per object basis using Django's language template tag i.e.:
{% load i18n %}
<h1>{% trans 'Page title' %}</h1>
<ul>
{% for obj in object_list %}
{% language obj.language_code %}
<li>{% trans 'view' %}: {{ obj.title }}
{% endlanguage %}
{% endfor %}
</ul>
We also use i18n_patterns so the urls of each object are language specific as well.
I'm stuck on how to convert this to Jinja. I cannot use Django's i18n template tags and cannot find something equivalent for Jinja.
I was also looking at Babel to help with extracting messages from the templates. So a solution that works with Babel as well as with Django would be preferred.
It turns out it's fairly simple to do this by writing a custom jinja2 extension (I've based this on the example in the jinja2 docs):
from django.utils import translation
from jinja2.ext import Extension, nodes
class LanguageExtension(Extension):
tags = {'language'}
def parse(self, parser):
lineno = next(parser.stream).lineno
# Parse the language code argument
args = [parser.parse_expression()]
# Parse everything between the start and end tag:
body = parser.parse_statements(['name:endlanguage'], drop_needle=True)
# Call the _switch_language method with the given language code and body
return nodes.CallBlock(self.call_method('_switch_language', args), [], [], body).set_lineno(lineno)
def _switch_language(self, language_code, caller):
with translation.override(language_code):
# Temporarily override the active language and render the body
output = caller()
return output
# Add jinja2's i18n extension
env.add_extension('jinja2.ext.i18n')
# Install Django's translation module as the gettext provider
env.install_gettext_translations(translation, newstyle=True)
# Add the language extension to the jinja2 environment
environment.add_extension(LanguageExtension)
With this extension in place switching the active translation language is pretty much exactly like how you'd do it in Django:
{% language 'en' %}{{ _('Hello World'){% endlanguage %}
The only caveat is that when using Django as a gettext provider and Babel as a message extractor it's important to tell Babel to set the message domain to django when running init/update/compile_catalog.
I have this code snippet to switch between languages in jinja2.
def change_lang(request, lang=None, *args, **kwargs):
"""
Get active page's url by a specified language, it activates
Usage: {{ change_lang(request, 'en') }}
"""
path = request.path
url_parts = resolve(path)
url = path
cur_language = get_language()
try:
activate(lang)
url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)
finally:
activate(cur_language)
return "%s" % url
in settings.py
TEMPLATES = [
{
"BACKEND": "django_jinja.backend.Jinja2",
'DIRS': [
os.path.join(BASE_DIR, 'templates/jinja'),
],
"OPTIONS": {
# Match the template names ending in .html but not the ones in the admin folder.
"match_extension": ".html",
"match_regex": r"^(?!admin/).*",
"newstyle_gettext": True,
"extensions": [
"jinja2.ext.do",
"jinja2.ext.loopcontrols",
"jinja2.ext.with_",
"jinja2.ext.i18n",
"jinja2.ext.autoescape",
"django_jinja.builtins.extensions.CsrfExtension",
"django_jinja.builtins.extensions.CacheExtension",
"django_jinja.builtins.extensions.TimezoneExtension",
"django_jinja.builtins.extensions.UrlsExtension",
"django_jinja.builtins.extensions.StaticFilesExtension",
"django_jinja.builtins.extensions.DjangoFiltersExtension",
],
'globals': {
'change_lang': 'drug.utils.change_lang'
},
"bytecode_cache": {
"name": "default",
"backend": "django_jinja.cache.BytecodeCache",
"enabled": False,
},
"autoescape": True,
"auto_reload": DEBUG,
"translation_engine": "django.utils.translation",
"context_processors": [
"dashboard.context_processors.auth",
# "django.template.context_processors.debug",
"django.template.context_processors.i18n",
# "django.template.context_processors.media",
# "django.template.context_processors.static",
# "django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages",
]
}
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
},
},]
and then you can use this in anywhere in your templates {{ _('Hello World') }}

Switch language in Django with the translated url redirect

I have internationalization correctly installed.
It's works with urls like:
/en/bookings/ #English
/es/reservas/ #Spanish
In the home page the language switching works fine too.
- What's the issue?
When I change the language in a translated page, like /en/bookings/, if I turn the language to Spanish (es) I am redirected to /en/bookings/ again and I see the page in English.
If I change the prefix (like this answer) the redirection goes to /es/bookings/ that doesn't exists.
I don't want to be redirected to the home page.
- What I like?
If I am in the /en/bookings/ and switch to Spanish I want to be redirected to /es/reservas/, for all the translated urls.
What is the best way?
Thanks.
I had similar problem so I sending my resolution to save Your time.
main(urls.py)
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
url(r'^', include('index.urls', namespace='index')),
)
(index.urls.py)
from django.conf.urls import url
from django.views.generic import TemplateView
from django.utils.translation import ugettext_lazy as _
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='index/index.html'), name='index'),
url(_(r'^python-programming/$'), TemplateView.as_view(template_name='index/new_page.html'),
name='new_page'),
]
Creating template tag to return urls for current location in all languages that we support (index.templatetags.helper_tags.py)
from django.template import Library
from django.core.urlresolvers import resolve, reverse
from django.utils.translation import activate, get_language
register = Library()
#register.simple_tag(takes_context=True)
def change_lang(context, lang=None, *args, **kwargs):
"""
Get active page's url by a specified language
Usage: {% change_lang 'en' %}
"""
path = context['request'].path
url_parts = resolve(path)
url = path
cur_language = get_language()
try:
activate(lang)
url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)
finally:
activate(cur_language)
return "%s" % url
Creating middleware to change site language when user will click at alternative link to this sub site but in different language
(middleware.py)
from django.utils import translation
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
class LangBasedOnUrlMiddleware(MiddlewareMixin):
#staticmethod
def process_request(request):
if hasattr(request, 'session'):
active_session_lang = request.session.get(translation.LANGUAGE_SESSION_KEY)
if active_session_lang == request.LANGUAGE_CODE:
return
if any(request.LANGUAGE_CODE in language for language in settings.LANGUAGES):
translation.activate(request.LANGUAGE_CODE)
request.session[translation.LANGUAGE_SESSION_KEY] = request.LANGUAGE_CODE
Adding it to (settings.py) just after LocaleMiddleware
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'our_app.middleware.LangBasedOnUrlMiddleware',
]
Sample usage in template:
{% load i18n %}
{% load helper_tags %}
{% get_available_languages as languages %}
{% for lang_code, lang_name in languages %}
<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{% change_lang lang_code %}">
{% endfor %}
When I had the same problem, I implemented a custom template tag (current_url) that, given the request in context, re-renders the url for the active language:
{% load custom_tags %}
<ul>
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
{# IMPORTANT! enclose the 'current_url' tag in a 'language' block #}
{% language language.code %}
<li {% if language.code == LANGUAGE_CODE %}class="active"{% endif %}>
{{ language.name_local }}
</li>
{% endlanguage %}
{% endfor %}
</ul>
Here is the code for the custom tag (custom_tags.py):
import six
import sys
from django.template import Node, TemplateSyntaxError, Library
from django.conf import settings
register = Library()
class CurrentURLNode(Node):
def __init__(self, asvar=None):
self.asvar = asvar
def render(self, context):
request = context['request']
from django.core.urlresolvers import reverse, NoReverseMatch
url = ''
try:
url = reverse(request.resolver_match.view_name, args=request.resolver_match.args, kwargs=request.resolver_match.kwargs, current_app=context.current_app)
except NoReverseMatch:
exc_info = sys.exc_info()
if settings.SETTINGS_MODULE:
project_name = settings.SETTINGS_MODULE.split('.')[0]
try:
url = reverse(project_name + '.' + request.resolver_match.view_name,
args=request.resolver_match.args, kwargs=request.resolver_match.kwargs,
current_app=context.current_app)
except NoReverseMatch:
if self.asvar is None:
six.reraise(*exc_info)
else:
if self.asvar is None:
raise
if self.asvar:
context[self.asvar] = url
return ''
else:
return url
#register.tag
def current_url(parser, token):
bits = token.split_contents()
bits = bits[1:]
asvar = None
if len(bits) >= 2 and bits[-2] == 'as':
asvar = bits[-1]
bits = bits[:-2]
if len(bits):
raise TemplateSyntaxError("Unexpected arguments to current_url tag")
return CurrentURLNode(asvar)
There is no need to use the 'set_language' django view. There is no need to make a POST request to change the active language. With only html archors linking all your internationalized content together, it's better for SEO.

How to upload a file in Django? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
What is the minimal example code needed for a "hello world" app using Django 1.3, that enables the user to upload a file?
Phew, Django documentation really does not have good example about this. I spent over 2 hours to dig up all the pieces to understand how this works. With that knowledge I implemented a project that makes possible to upload files and show them as list. To download source for the project, visit https://github.com/axelpale/minimal-django-file-upload-example or clone it:
> git clone https://github.com/axelpale/minimal-django-file-upload-example.git
Update 2013-01-30: The source at GitHub has also implementation for Django 1.4 in addition to 1.3. Even though there is few changes the following tutorial is also useful for 1.4.
Update 2013-05-10: Implementation for Django 1.5 at GitHub. Minor changes in redirection in urls.py and usage of url template tag in list.html. Thanks to hubert3 for the effort.
Update 2013-12-07: Django 1.6 supported at GitHub. One import changed in myapp/urls.py. Thanks goes to Arthedian.
Update 2015-03-17: Django 1.7 supported at GitHub, thanks to aronysidoro.
Update 2015-09-04: Django 1.8 supported at GitHub, thanks to nerogit.
Update 2016-07-03: Django 1.9 supported at GitHub, thanks to daavve and nerogit
Project tree
A basic Django 1.3 project with single app and media/ directory for uploads.
minimal-django-file-upload-example/
src/
myproject/
database/
sqlite.db
media/
myapp/
templates/
myapp/
list.html
forms.py
models.py
urls.py
views.py
__init__.py
manage.py
settings.py
urls.py
1. Settings: myproject/settings.py
To upload and serve files, you need to specify where Django stores uploaded files and from what URL Django serves them. MEDIA_ROOT and MEDIA_URL are in settings.py by default but they are empty. See the first lines in Django Managing Files for details. Remember also set the database and add myapp to INSTALLED_APPS
...
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'database.sqlite3'),
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
...
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
...
INSTALLED_APPS = (
...
'myapp',
)
2. Model: myproject/myapp/models.py
Next you need a model with a FileField. This particular field stores files e.g. to media/documents/2011/12/24/ based on current date and MEDIA_ROOT. See FileField reference.
# -*- coding: utf-8 -*-
from django.db import models
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
3. Form: myproject/myapp/forms.py
To handle upload nicely, you need a form. This form has only one field but that is enough. See Form FileField reference for details.
# -*- coding: utf-8 -*-
from django import forms
class DocumentForm(forms.Form):
docfile = forms.FileField(
label='Select a file',
help_text='max. 42 megabytes'
)
4. View: myproject/myapp/views.py
A view where all the magic happens. Pay attention how request.FILES are handled. For me, it was really hard to spot the fact that request.FILES['docfile'] can be saved to models.FileField just like that. The model's save() handles the storing of the file to the filesystem automatically.
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from myproject.myapp.models import Document
from myproject.myapp.forms import DocumentForm
def list(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('myapp.views.list'))
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render_to_response(
'myapp/list.html',
{'documents': documents, 'form': form},
context_instance=RequestContext(request)
)
5. Project URLs: myproject/urls.py
Django does not serve MEDIA_ROOT by default. That would be dangerous in production environment. But in development stage, we could cut short. Pay attention to the last line. That line enables Django to serve files from MEDIA_URL. This works only in developement stage.
See django.conf.urls.static.static reference for details. See also this discussion about serving media files.
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns('',
(r'^', include('myapp.urls')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
6. App URLs: myproject/myapp/urls.py
To make the view accessible, you must specify urls for it. Nothing special here.
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views',
url(r'^list/$', 'list', name='list'),
)
7. Template: myproject/myapp/templates/myapp/list.html
The last part: template for the list and the upload form below it. The form must have enctype-attribute set to "multipart/form-data" and method set to "post" to make upload to Django possible. See File Uploads documentation for details.
The FileField has many attributes that can be used in templates. E.g. {{ document.docfile.url }} and {{ document.docfile.name }} as in the template. See more about these in Using files in models article and The File object documentation.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Minimal Django File Upload Example</title>
</head>
<body>
<!-- List of uploaded documents -->
{% if documents %}
<ul>
{% for document in documents %}
<li>{{ document.docfile.name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No documents.</p>
{% endif %}
<!-- Upload form. Note enctype attribute! -->
<form action="{% url 'list' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload" /></p>
</form>
</body>
</html>
8. Initialize
Just run syncdb and runserver.
> cd myproject
> python manage.py syncdb
> python manage.py runserver
Results
Finally, everything is ready. On default Django developement environment the list of uploaded documents can be seen at localhost:8000/list/. Today the files are uploaded to /path/to/myproject/media/documents/2011/12/17/ and can be opened from the list.
I hope this answer will help someone as much as it would have helped me.
Demo
See the github repo, works with Django 3
A minimal Django file upload example
1. Create a django project
Run startproject::
$ django-admin.py startproject sample
now a folder(sample) is created.
2. create an app
Create an app::
$ cd sample
$ python manage.py startapp uploader
Now a folder(uploader) with these files are created::
uploader/
__init__.py
admin.py
app.py
models.py
tests.py
views.py
migrations/
__init__.py
3. Update settings.py
On sample/settings.py add 'uploader' to INSTALLED_APPS and add MEDIA_ROOT and MEDIA_URL, ie::
INSTALLED_APPS = [
'uploader',
...<other apps>...
]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
4. Update urls.py
in sample/urls.py add::
...<other imports>...
from django.conf import settings
from django.conf.urls.static import static
from uploader import views as uploader_views
urlpatterns = [
...<other url patterns>...
path('', uploader_views.UploadView.as_view(), name='fileupload'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
5. Update models.py
update uploader/models.py::
from django.db import models
class Upload(models.Model):
upload_file = models.FileField()
upload_date = models.DateTimeField(auto_now_add =True)
6. Update views.py
update uploader/views.py::
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import Upload
class UploadView(CreateView):
model = Upload
fields = ['upload_file', ]
success_url = reverse_lazy('fileupload')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['documents'] = Upload.objects.all()
return context
7. create templates
Create a folder sample/uploader/templates/uploader
Create a file upload_form.html ie sample/uploader/templates/uploader/upload_form.html::
<div style="padding:40px;margin:40px;border:1px solid #ccc">
<h1>Django File Upload</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form><hr>
<ul>
{% for document in documents %}
<li>
{{ document.upload_file.name }}
<small>({{ document.upload_file.size|filesizeformat }}) - {{document.upload_date}}</small>
</li>
{% endfor %}
</ul>
</div>
8. Syncronize database
Syncronize database and runserver::
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver
visit http://localhost:8000/
Generally speaking when you are trying to 'just get a working example' it is best to 'just start writing code'. There is no code here to help you with, so it makes answering the question a lot more work for us.
If you want to grab a file, you need something like this in an html file somewhere:
<form method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" name="submit" value="Upload" />
</form>
That will give you the browse button, an upload button to start the action (submit the form) and note the enctype so Django knows to give you request.FILES
In a view somewhere you can access the file with
def myview(request):
request.FILES['myfile'] # this is my file
There is a huge amount of information in the file upload docs
I recommend you read the page thoroughly and just start writing code - then come back with examples and stack traces when it doesn't work.
I must say I find the documentation at django confusing.
Also for the simplest example why are forms being mentioned?
The example I got to work in the views.py is :-
for key, file in request.FILES.items():
path = file.name
dest = open(path, 'w')
if file.multiple_chunks:
for c in file.chunks():
dest.write(c)
else:
dest.write(file.read())
dest.close()
The html file looks like the code below, though this example only uploads one file and the code to save the files handles many :-
<form action="/upload_file/" method="post" enctype="multipart/form-data">{% csrf_token %}
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
These examples are not my code, they have been optained from two other examples I found.
I am a relative beginner to django so it is very likely I am missing some key point.
I also had the similar requirement. Most of the examples on net are asking to create models and create forms which I did not wanna use. Here is my final code.
if request.method == 'POST':
file1 = request.FILES['file']
contentOfFile = file1.read()
if file1:
return render(request, 'blogapp/Statistics.html', {'file': file1, 'contentOfFile': contentOfFile})
And in HTML to upload I wrote:
{% block content %}
<h1>File content</h1>
<form action="{% url 'blogapp:uploadComplete'%}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input id="uploadbutton" type="file" value="Browse" name="file" accept="text/csv" />
<input type="submit" value="Upload" />
</form>
{% endblock %}
Following is the HTML which displays content of file:
{% block content %}
<h3>File uploaded successfully</h3>
{{file.name}}
</br>content = {{contentOfFile}}
{% endblock %}
Extending on Henry's example:
import tempfile
import shutil
FILE_UPLOAD_DIR = '/home/imran/uploads'
def handle_uploaded_file(source):
fd, filepath = tempfile.mkstemp(prefix=source.name, dir=FILE_UPLOAD_DIR)
with open(filepath, 'wb') as dest:
shutil.copyfileobj(source, dest)
return filepath
You can call this handle_uploaded_file function from your view with the uploaded file object. This will save the file with a unique name (prefixed with filename of the original uploaded file) in filesystem and return the full path of saved file. You can save the path in database, and do something with the file later.
Here it may helps you:
create a file field in your models.py
For uploading the file(in your admin.py):
def save_model(self, request, obj, form, change):
url = "http://img.youtube.com/vi/%s/hqdefault.jpg" %(obj.video)
url = str(url)
if url:
temp_img = NamedTemporaryFile(delete=True)
temp_img.write(urllib2.urlopen(url).read())
temp_img.flush()
filename_img = urlparse(url).path.split('/')[-1]
obj.image.save(filename_img,File(temp_img)
and use that field in your template also.
You can refer to server examples in Fine Uploader, which has django version.
https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader
It's very elegant and most important of all, it provides featured js lib. Template is not included in server-examples, but you can find demo on its website.
Fine Uploader: http://fineuploader.com/demos.html
django-fine-uploader
views.py
UploadView dispatches post and delete request to respective handlers.
class UploadView(View):
#csrf_exempt
def dispatch(self, *args, **kwargs):
return super(UploadView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
"""A POST request. Validate the form and then handle the upload
based ont the POSTed data. Does not handle extra parameters yet.
"""
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_upload(request.FILES['qqfile'], form.cleaned_data)
return make_response(content=json.dumps({ 'success': True }))
else:
return make_response(status=400,
content=json.dumps({
'success': False,
'error': '%s' % repr(form.errors)
}))
def delete(self, request, *args, **kwargs):
"""A DELETE request. If found, deletes a file with the corresponding
UUID from the server's filesystem.
"""
qquuid = kwargs.get('qquuid', '')
if qquuid:
try:
handle_deleted_file(qquuid)
return make_response(content=json.dumps({ 'success': True }))
except Exception, e:
return make_response(status=400,
content=json.dumps({
'success': False,
'error': '%s' % repr(e)
}))
return make_response(status=404,
content=json.dumps({
'success': False,
'error': 'File not present'
}))
forms.py
class UploadFileForm(forms.Form):
""" This form represents a basic request from Fine Uploader.
The required fields will **always** be sent, the other fields are optional
based on your setup.
Edit this if you want to add custom parameters in the body of the POST
request.
"""
qqfile = forms.FileField()
qquuid = forms.CharField()
qqfilename = forms.CharField()
qqpartindex = forms.IntegerField(required=False)
qqchunksize = forms.IntegerField(required=False)
qqpartbyteoffset = forms.IntegerField(required=False)
qqtotalfilesize = forms.IntegerField(required=False)
qqtotalparts = forms.IntegerField(required=False)
Not sure if there any disadvantages to this approach but even more minimal, in views.py:
entry = form.save()
# save uploaded file
if request.FILES['myfile']:
entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True)
I faced the similar problem, and solved by django admin site.
# models
class Document(models.Model):
docfile = models.FileField(upload_to='documents/Temp/%Y/%m/%d')
def doc_name(self):
return self.docfile.name.split('/')[-1] # only the name, not full path
# admin
from myapp.models import Document
class DocumentAdmin(admin.ModelAdmin):
list_display = ('doc_name',)
admin.site.register(Document, DocumentAdmin)