Creating a file uploading system in Django - django

In my Django application I intend to create a file uploading system which puts the user uploaded files in a data folder. In order to do this I followed online tutorials Link 1 Link 2 and coded a below simple application. But it is producing error
PermissionError: [Errno 13] Permission denied: '/data'
Project Structure
<project_name>
|--data
|--<app_name>
|--<project_name>
|--manage.py
index.html
<div class="custom-file">
<input type="file" class="custom-file-input" id="fileupload" name="fileupload" multiple required>
<label class="custom-file-label" for="fileupload">Choose files</label>
</div>
view.py
from django.core.files.storage import FileSystemStorage
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def upload(request):
files = request.FILES.getlist('fileupload')
fs = FileSystemStorage(location="/data/upload/")
for fl in files:
fs.save(fl.name, fl)
settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'data')

Creating multiple file upload should handle in the form.
Take a look at Uploading multiple files
In your forms.py
from django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
In your views.py
from django.views.generic.edit import FormView
from .forms import FileFieldForm
class FileFieldView(FormView):
form_class = FileFieldForm
template_name = 'upload.html' # Replace with your template.
success_url = '...' # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file_field')
if form.is_valid():
for f in files:
... # Do something with each file.
return self.form_valid(form)
else:
return self.form_invalid(form)

Related

Django - Render is not working in my project

I am dealing with form like 1 week but couldn't solve my issue. Probably i overlook something that can be found easy by other eyes, but totally, i don't know what to do. I recognize problem by starting build form. I had to use render for form and it failed in every try. I am able to connect db and showing data in html pages but whenever i use render instead of render_to_response it is failing. And i had to use render for post request as i know. Not only for form, render is not working for all. Even for a simple: def home(request): context = {'foo': 'bar'} return render(request, 'main.html', context)
models.py
class ModuleNames(models.Model):
ModuleName = models.CharField(max_length = 50)
ModuleDesc = models.CharField(max_length = 256)
ModuleSort = models.SmallIntegerField()
isActive = models.BooleanField()
ModuleType = models.ForeignKey(ModuleTypes, on_delete=models.CASCADE, null = True)
slug = models.SlugField(('ModuleName'), max_length=50, blank=True)
class Meta:
app_label = 'zz'
def __unicode__(self):
return self.status
forms.py
from django import forms
from MyApp.models import ModuleNames
class ModuleForm(forms.ModelForm):
moduleName = forms.CharField(label='Module Name', max_length=50)
ModuleDesc = forms.CharField(max_length = 256)
ModuleSort = forms.IntegerField()
isActive = forms.BooleanField()
ModuleType = forms.IntegerField()
class Meta:
model = ModuleNames
fields =('moduleName','ModuleDesc','ModuleSort','isActive','ModuleType')
view.py
from django.views.generic import TemplateView
from django.shortcuts import render,render_to_response, redirect
from django.template import RequestContext
import json
from django.core.serializers.json import Serializer
from django.http import HttpResponse, Http404, HttpResponseRedirect
from urllib.parse import urlparse
from django.urls import resolve
from django.db import connection
from collections import namedtuple
from django.db.models import F
from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect
from MyApp.models import ModuleNames
from MyApp.forms import ModuleForm
def AddNewModule(request):
template_name = 'addnewmodule.html'
if request.method == 'GET':
form = ModuleForm()
posts = ModuleNames.objects.all()
args = {'form': form, 'posts': posts }
return render(request, template_name, args) #This part is showing data when i use render_to_response. But after clicking Save button on html page, it will give below first error.
if request.method == 'POST':
form = ModuleForm(request.POST)
if form.is_valid():
form.pop('csrfmiddlewaretoken', None)
post = form.save(commit=False)
post.save()
text = form.cleaned_data['post']
form = ModuleForm()
args = {'form': form, 'text': text}
return render(request, template_name, args)
Error that i have when using render_to_response
Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF token missing or incorrect.
Error when i use render for any function
Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/addnewmodule
Django Version: 2.1.3
Python Version: 3.7.1
Installed Applications:
['MyApp',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/exception.py" in inner
34.response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
126.response = self.process_exception_by_middleware(e, request)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
124.response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/Cem/Documents/Projects/Python/Web/FirstApp/MyApp/views.py" in addnewmodule
132.return render(request, template_name, args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/shortcuts.py" in render
36.content = loader.render_to_string(template_name, context, request, using=using)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/template/loader.py" in render_to_string
62.return template.render(context, request)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/template/backends/django.py" in render
61.return self.template.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/template/base.py" in render
169.with context.bind_template(self):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py" in __enter__
112.return next(self.gen)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/template/context.py" in bind_template
246.updates.update(processor(self.request))
Exception Type: TypeError at /addnewmodule
Exception Value: 'module' object is not callable
Read about CSRF tokens in django, it's used for site protection/
You are missing the the csrf_token in your addnewmodule.html form, so,
you can get back to addnewmodule.html form and add the {% csrf_token %}just below the tag form action="" method="POST" like this
<form action="" method="POST">
{% csrf_token %}

Upload File in Django (not working)

I am creating a bulletin here containing threads. Each thread includes one image and then the thread can be extended with posts.
It's like 4chan.
The models isn't saved in the database. I followed this answer to create an file upload example.
The forum app contains a simple file upload example and the upload objects do get saved there.
Codebase (github)
The project tree
bookstore/
chan/
templates/chan/index.html
forms.py
admin.py
views.py
urls.py
forum/
...
bookstore/
settings.py
urls.py
Settings
.
.
.
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Urls.py
from django.conf.urls import url, include
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^create_post/(?P<thread_id>[0-9]+)/$', views.create_post, name='create_post'),
url(r'^create_thread/$', views.create_thread, name='create_thread'),
]
Views
from django.shortcuts import render, redirect
from . import models
from . import forms
def index(request):
threads = models.Thread.objects.all()
thread_form = forms.Thread()
post_form = forms.Post()
return render(request, 'chan/index.html',{
'threads':threads,
'thread_form':thread_form,
'post_form':post_form,
})
def create_post(request, thread_id):
form = forms.Post(request.POST, request.FILES)
if form.is_valid():
post = Post(
text=request.POST['text'],
document=request.FILES['document'],
thread=models.Thread.get(pk=thread_id),
)
post.save()
return redirect('chan:index')
def create_thread(request):
form = forms.Thread(request.POST, request.FILES)
if form.is_valid():
thread = Thread(
text=request.POST['text'],
document=request.FILES['document']
)
thread.save()
return redirect('chan:index')
I've been on this for hours now checking for anything that I might've missed.
Honestly I have no idea what's you are trying to do. But when I look into that repo the hole thing is messed up. I have a few questions for you...
Why you don't have __init__.py? ( hole repo doesn't have, not good )
Best practise:
Place init.py file and call the module with from module import something
Why you don't have action attribute ?
You have url={% ...} but you should have action={%...}

Keeping custom sign_up class and importing allauth forms in same forms.py file causing import errors

from django import forms
from allauth.account.forms import (LoginForm, ChangePasswordForm,
ResetPasswordForm, SetPasswordForm, ResetPasswordKeyForm)
from django.contrib.auth import get_user_model
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, HTML, Button, Row, Field
from crispy_forms.bootstrap import AppendedText, PrependedText, FormActions
from django.core.urlresolvers import reverse
class MySignupForm(forms.Form):
class Meta:
model = get_user_model()
fields = ['email', 'first_name', 'last_name']
def __init__(self, *args, **kwargs):
super(MySignupForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.fields["email"].widget.input_type = "email" # ugly hack
self.helper.form_method = "POST"
self.helper.form_action = "account_signup"
self.helper.form_id = "signup_form"
self.helper.form_class = "signup"
self.helper.layout = Layout(
Field('email', placeholder="Enter Email", autofocus=""),
Field('first_name', placeholder="Enter First Name"),
Field('last_name', placeholder="Enter Last Name"),
Field('password1', placeholder="Enter Password"),
Field('password2', placeholder="Re-enter Password"),
Submit('sign_up', 'Sign up', css_class="btn-warning"),
)
def signup(self, request, user):
pass
class MyLoginForm(LoginForm):
remember_me = forms.BooleanField(required=False, initial=False)
def __init__(self, *args, **kwargs):
super(MyLoginForm, self).__init__(*args, **kwargs)
class MyPasswordChangeForm(ChangePasswordForm):
def __init__(self, *args, **kwargs):
super(MyPasswordChangeForm, self).__init__(*args, **kwargs)
I have structure like this in my app.forms.py file, where i am importing allauth built in forms LoginForm ResetPasswordForm etc. and in the same file i am defining custom signup class.
hook for custom signup class:
ACCOUNT_SIGNUP_FORM_CLASS = 'allauth_core.forms.MySignupForm'
I think i am hitting circular import issue but not sure why ?
File "/Users/rmahamuni/.virtualenvs/todo/lib/python2.7/site-packages/allauth/urls.py", line 8, in
urlpatterns = [url('^', include('allauth.account.urls'))]
File "/Users/rmahamuni/.virtualenvs/todo/lib/python2.7/site-packages/django/conf/urls/init.py", line 52, in include
urlconf_module = import_module(urlconf_module)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/init.py", line 37, in import_module
import(name)
File "/Users/rmahamuni/.virtualenvs/todo/lib/python2.7/site-packages/allauth/account/urls.py", line 4, in
from . import views
File "/Users/rmahamuni/.virtualenvs/todo/lib/python2.7/site-packages/allauth/account/views.py", line 19, in
from .forms import (
File "/Users/rmahamuni/.virtualenvs/todo/lib/python2.7/site-packages/allauth/account/forms.py", line 206, in
class BaseSignupForm(_base_signup_form_class()):
File "/Users/rmahamuni/.virtualenvs/todo/lib/python2.7/site-packages/allauth/account/forms.py", line 188, in _base_signup_form_class
' "%s"' % (fc_module, e))
django.core.exceptions.ImproperlyConfigured: Error importing form class allauth_core.forms: "cannot import name ChangePasswordForm"
If i keep custom signup form in separate file then i dont get this issue.
I tried switching installed apps lineup
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth_core', <-- app where form is located.
What am i missing here ? can someone please guide me ? Thanks
This happens because allauth tries to import the given module/class you specified as signup form in your settings.py in its account/forms.py. (See forms.py#L186 # github)
When you override other forms like ChangePasswordForm in your settings.py by importing allauth's account/forms.py, circular import happens because allauth has already imported your forms.py in its forms.py
To avoid this, simply move your singup form to a separate signupform.py and change the settings accordingly. It'll work.

Using static images with sorl-thumbnail

I am trying to serve the thumbnail of a file that resides in my STATIC_ROOT folder. It doesn't really matter if it ends up in MEDIA_URL/cache, but sorl-thumbnail will not load the image from the static folder.
current code:
{% thumbnail "images/store/no_image.png" "125x125" as thumb %}
hack that works
{% thumbnail "http://localhost/my_project/static/images/store/no_image.png" "125x125" as thumb %}
I don't like the hack because
A) It is not dry (my project is actually served from a sub-directory of /
B) It is using http to grab a file that is only 3 directories away, seems pointlessly inefficient
I worked around this by passing through a file to the template context from my view.
Here is an example util function I called from my views:
def get_placeholder_image():
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
placeholder = storage.open(settings.PLACEHOLDER_IMAGE_PATH)
image = ImageFile(placeholder)
image.storage = storage
return image
You could probably do something similar as a custom template tag.
Template filter works. But I am not sure, whether there is each time reading from storage. If so, it is unreasonably...
from django.template import Library
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
register = Library()
#register.filter
def static_image(path):
"""
{% thumbnail "/img/default_avatar.png"|static_image "50x50" as img %}
<img src="{{ MEDIA_URL }}{{img}}"/>
{% endthumbnail %}
"""
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
image = ImageFile(storage.open(path))
image.storage = storage
return image
Assuming you are using Django 1.3 you should take a look at the docs about Managing static files
If you setup everything correctly, you can include your images like this:
<img src="{{ STATIC_URL }}images/store/no_image.png" />
I ended up hijacking the fact that it can get from a URL, and wrote my own tag that overrides the _render method on the ThumbnailNode:
from django.template import Library
from django.contrib.sites.models import Site
from django.contrib.sites.models import get_current_site
from sorl.thumbnail.templatetags.thumbnail import ThumbnailNode as SorlNode
from sorl.thumbnail.conf import settings
from sorl.thumbnail.images import DummyImageFile
from sorl.thumbnail import default
register = Library()
class ThumbnailNode(SorlNode):
"""allows to add site url prefix"""
def _render(self, context):
file_ = self.file_.resolve(context)
if isinstance(file_, basestring):
site = get_current_site(context['request'])
file_ = "http://" + site.domain + file_
geometry = self.geometry.resolve(context)
options = {}
for key, expr in self.options:
noresolve = {u'True': True, u'False': False, u'None': None}
value = noresolve.get(unicode(expr), expr.resolve(context))
if key == 'options':
options.update(value)
else:
options[key] = value
if settings.THUMBNAIL_DUMMY:
thumbnail = DummyImageFile(geometry)
elif file_:
thumbnail = default.backend.get_thumbnail(
file_, geometry, **options
)
else:
return self.nodelist_empty.render(context)
context.push()
context[self.as_var] = thumbnail
output = self.nodelist_file.render(context)
context.pop()
return output
#register.tag
def thumbnail(parser, token):
return ThumbnailNode(parser, token)
Then from the template:
{% with path=STATIC_URL|add:"/path/to/static/image.png" %}
{% thumbnail path "50x50" as thumb %}
<img src="{{ thumb.url }}" />
...
Not the neatest solution... :-/
The default value of setting sorl THUMBNAIL_STORAGE is the same settings.DEFAULT_FILE_STORAGE.
You must create storage that uses STATIC_ROOT, for example you can use 'django.core.files.storage.FileSystemStorage' and instantiate with location=settings.STATIC_ROOT and base_url=settings.STATIC_URL
Only THUMBNAIL_STORAGE set in settings for a 'MyCustomFileStorage' did not work. So I had to do to DEFAULT_FILE_STORAGE and it worked.
Define in settings.py:
DEFAULT_FILE_STORAGE = 'utils.storage.StaticFilesStorage'
utils/storage.py:
import os
from datetime import datetime
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.core.exceptions import ImproperlyConfigured
def check_settings():
"""
Checks if the MEDIA_(ROOT|URL) and STATIC_(ROOT|URL)
settings have the same value.
"""
if settings.MEDIA_URL == settings.STATIC_URL:
raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL "
"settings must have different values")
if (settings.MEDIA_ROOT == settings.STATIC_ROOT):
raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT "
"settings must have different values")
class TimeAwareFileSystemStorage(FileSystemStorage):
def accessed_time(self, name):
return datetime.fromtimestamp(os.path.getatime(self.path(name)))
def created_time(self, name):
return datetime.fromtimestamp(os.path.getctime(self.path(name)))
def modified_time(self, name):
return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
class StaticFilesStorage(TimeAwareFileSystemStorage):
"""
Standard file system storage for static files.
The defaults for ``location`` and ``base_url`` are
``STATIC_ROOT`` and ``STATIC_URL``.
"""
def __init__(self, location=None, base_url=None, *args, **kwargs):
if location is None:
location = settings.STATIC_ROOT
if base_url is None:
base_url = settings.STATIC_URL
if not location:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_ROOT setting. Set it to "
"the absolute path of the directory that holds static files.")
# check for None since we might use a root URL (``/``)
if base_url is None:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_URL setting. Set it to "
"URL that handles the files served from STATIC_ROOT.")
if settings.DEBUG:
check_settings()
super(StaticFilesStorage, self).__init__(location, base_url, *args, **kwargs)
Reference:
https://github.com/mneuhaus/heinzel/blob/master/staticfiles/storage.py
https://docs.djangoproject.com/en/dev/ref/settings/#default-file-storage

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)