Нужен минимальный пример загрузки файла Django
Как новичок в Django, я испытываю трудности при создании приложения для загрузки в Django 1.3. Я не смог найти ни одного актуального примера / фрагмента. Может ли кто-нибудь опубликовать для этого минимальный, но полный пример кода (Model, View, Template)?
10 ответов
Уф, документация Django действительно не имеет хорошего примера по этому поводу. Я потратил более 2 часов, чтобы выкопать все кусочки, чтобы понять, как это работает. С этим знанием я реализовал проект, который позволяет загружать файлы и показывать их в виде списка. Чтобы загрузить исходный код проекта, посетите https://github.com/axelpale/minimal-django-file-upload-example или клонируйте его:
> git clone https://github.com/axelpale/minimal-django-file-upload-example.git
Обновление 2013-01-30: у источника на GitHub есть также реализация для Django 1.4 в дополнение к 1.3. Несмотря на то, что изменений немного, следующий урок также полезен для 1.4.
Обновление 2013-05-10: реализация для Django 1.5 на GitHub. Незначительные изменения в перенаправлении в urls.py и использование тега шаблона URL в list.html. Спасибо hubert3 за усилия.
Обновление 2013-12-07: Django 1.6 поддерживается на GitHub. Один импорт изменен в myapp / urls.py. Спасибо идет в Arthedian.
Обновление 2015-03-17: Django 1.7 поддерживается на GitHub, благодаря aronysidoro.
Обновление 2015-09-04: Django 1.8 поддерживается на GitHub, благодаря nerogit.
Обновление 2016-07-03: Django 1.9 поддерживается на GitHub, благодаря daavve и nerogit
Дерево проекта
Базовый проект Django 1.3 с одним приложением и медиа / каталогом для загрузки.
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. Настройки: myproject/settings.py
Чтобы загружать и обслуживать файлы, вам нужно указать, где Django хранит загруженные файлы и с какого URL Django их обслуживает. MEDIA_ROOT и MEDIA_URL находятся в settings.py по умолчанию, но они пусты. Подробности смотрите в первых строках Django Managing Files. Не забудьте также установить базу данных и добавить myapp в 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. Модель: myproject/myapp/models.py
Далее вам нужна модель с FileField. В этом конкретном поле хранятся файлы, например, в media/documents/2011/12/24/ на основе текущей даты и MEDIA_ROOT. Смотрите ссылку на FileField.
# -*- coding: utf-8 -*-
from django.db import models
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
3. Форма: myproject/myapp/forms.py
Чтобы справиться с загрузкой, вам нужна форма. Эта форма имеет только одно поле, но этого достаточно. См. Ссылку FileField формы для деталей.
# -*- coding: utf-8 -*-
from django import forms
class DocumentForm(forms.Form):
docfile = forms.FileField(
label='Select a file',
help_text='max. 42 megabytes'
)
4. Просмотр: myproject / myapp / views.py
Вид, где происходит вся магия. Обратите внимание, как request.FILES
обрабатываются Для меня было действительно трудно заметить тот факт, что request.FILES['docfile']
может быть сохранен в модели. FileField просто так. Модель save() автоматически обрабатывает сохранение файла в файловой системе.
# -*- 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. URL проекта: myproject / urls.py
Django не обслуживает MEDIA_ROOT по умолчанию. Это было бы опасно в производственной среде. Но на стадии разработки мы могли бы прервать. Обратите внимание на последнюю строчку. Эта строка позволяет Django обслуживать файлы из MEDIA_URL. Это работает только в стадии разработки.
См. Django.conf.urls.static.static ссылку для деталей. Смотрите также это обсуждение об обслуживании медиа-файлов.
# -*- 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. URL-адреса приложений: myproject / myapp / urls.py
Чтобы сделать представление доступным, вы должны указать для него URL-адреса. Здесь нет ничего особенного.
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views',
url(r'^list/$', 'list', name='list'),
)
7. Шаблон: myproject / myapp / templates / myapp / list.html
Последняя часть: шаблон для списка и форма для загрузки под ним. Форма должна иметь атрибут enctype, установленный в "multipart / form-data", и метод, установленный в "post", чтобы сделать возможной загрузку в Django. Подробнее смотрите в документации по загрузке файлов.
FileField имеет много атрибутов, которые можно использовать в шаблонах. Например, {{ document.docfile.url }} и {{ document.docfile.name }} как в шаблоне. Подробнее об этом см. В статье " Использование файлов в моделях" и документации по объекту "Файл".
<!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><a href="{{ document.docfile.url }}">{{ document.docfile.name }}</a></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. Инициализировать
Просто запустите syncdb и runserver.
> cd myproject
> python manage.py syncdb
> python manage.py runserver
Результаты
Наконец-то все готово. По умолчанию в среде разработки Django список загруженных документов можно посмотреть по адресу localhost:8000/list/
, Сегодня файлы загружаются в /path/to/myproject/media/documents/2011/12/17/ и могут быть открыты из списка.
Я надеюсь, что этот ответ поможет кому-то так же сильно, как и мне.
демонстрация
Обновление ответа Аксели Пален. посмотреть репозиторий github, работает с Django 2
Минимальный пример загрузки файла Django
1. Создайте проект Django
Запустите startproject::
$ django-admin.py startproject sample
теперь папка (образец) создана::
sample/
manage.py
sample/
__init__.py
settings.py
urls.py
wsgi.py
2. создать приложение
Создать приложение::
$ cd sample
$ python manage.py startapp uploader
Сейчас папка (uploader
) с этими файлами создаются::
uploader/
__init__.py
admin.py
app.py
models.py
tests.py
views.py
migrations/
__init__.py
3. Обновите settings.py
На sample/settings.py
добавлять 'uploader.apps.UploaderConfig'
в INSTALLED_APPS
и добавить MEDIA_ROOT
а также MEDIA_URL
, т.е.
INSTALLED_APPS = [
...<other apps>...
'uploader.apps.UploaderConfig',
]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
4. Обновите urls.py
в sample/urls.py
добавлять::
...<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.home, name='imageupload'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
5. Обновите models.py
Обновить uploader/models.py
::
from django.db import models
from django.forms import ModelForm
class Upload(models.Model):
pic = models.FileField(upload_to="images/")
upload_date=models.DateTimeField(auto_now_add =True)
# FileUpload form class.
class UploadForm(ModelForm):
class Meta:
model = Upload
fields = ('pic',)
6. Обновите views.py
Обновить uploader/views.py
::
from django.shortcuts import render
from uploader.models import UploadForm,Upload
from django.http import HttpResponseRedirect
from django.urls import reverse
# Create your views here.
def home(request):
if request.method=="POST":
img = UploadForm(request.POST, request.FILES)
if img.is_valid():
img.save()
return HttpResponseRedirect(reverse('imageupload'))
else:
img=UploadForm()
images=Upload.objects.all().order_by('-upload_date')
return render(request,'home.html',{'form':img,'images':images})
7. создавать шаблоны
Создайте папку с шаблонами в папке uploader, затем создайте файл home.html, т.е. sample/uploader/templates/home.html
::
<div style="padding:40px;margin:40px;border:1px solid #ccc">
<h1>picture</h1>
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %} {{form}}
<input type="submit" value="Upload" />
</form>
{% for img in images %}
{{forloop.counter}}.<a href="{{ img.pic.url }}">{{ img.pic.name }}</a>
({{img.upload_date}})<hr />
{% endfor %}
</div>
8. Синхронизировать базу данных
Синхронизировать базу данных и сервер запуска::
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver
посетите http://localhost.com:8000/
Вообще говоря, когда вы пытаетесь "просто получить рабочий пример", лучше всего "просто начать писать код". Здесь нет кода, чтобы помочь вам, поэтому он делает ответ на этот вопрос намного больше работы для нас.
Если вы хотите получить файл, вам нужно что-то вроде этого в html-файле:
<form method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" name="submit" value="Upload" />
</form>
Это даст вам кнопку обзора, кнопку загрузки, чтобы начать действие (отправить форму) и отметить энктип, чтобы Django знал, чтобы дать вам request.FILES
В представлении где-то вы можете получить доступ к файлу с
def myview(request):
request.FILES['myfile'] # this is my file
Существует огромное количество информации в файлах загрузки документов.
Я рекомендую вам внимательно прочитать страницу и просто начать писать код, а затем возвращаться с примерами и трассировкой стека, когда она не работает.
Я должен сказать, что нахожу документацию в Django запутанной. Также для простейшего примера, почему упоминаются формы? Пример, который я получил для работы в views.py:
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()
HTML-файл выглядит как приведенный ниже код, хотя в этом примере загружается только один файл, а код для сохранения файлов обрабатывает много:-
<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>
Эти примеры не являются моим кодом, они были получены из двух других примеров, которые я нашел. Я относительный новичок в Django, поэтому очень вероятно, что я упускаю какой-то ключевой момент.
У меня тоже было подобное требование. Большинство примеров в сети просят создать модели и формы, которые я не хотел использовать. Вот мой окончательный код.
if request.method == 'POST':
file1 = request.FILES['file']
contentOfFile = file1.read()
if file1:
return render(request, 'blogapp/Statistics.html', {'file': file1, 'contentOfFile': contentOfFile})
И в HTML для загрузки я написал:
{% 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 %}
Ниже приведен HTML-код, который отображает содержимое файла:
{% block content %}
<h3>File uploaded successfully</h3>
{{file.name}}
</br>content = {{contentOfFile}}
{% endblock %}
Продолжая на примере Генри:
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
Вы можете назвать это handle_uploaded_file
Функция с вашей точки зрения с загруженным объектом файла. Это сохранит файл с уникальным именем (с префиксом имени файла исходного загруженного файла) в файловой системе и вернет полный путь сохраненного файла. Вы можете сохранить путь в базе данных и что-то сделать с файлом позже.
Здесь это может вам помочь: создайте поле файла в вашем models.py
Для загрузки файла (в вашем 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)
и используйте это поле в вашем шаблоне.
Вы можете обратиться к примерам сервера в Fine Uploader, который имеет версию django. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader
Это очень элегантный и самый важный из всех, он предоставляет JS lib. Шаблон не включен в примеры серверов, но вы можете найти демо на его сайте. Fine Uploader: http://fineuploader.com/demos.html
Джанго-тонкий загрузчик
views.py
UploadView отправляет запрос на публикацию и удаление соответствующим обработчикам.
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)
Не уверен, есть ли какие-либо недостатки у этого подхода, но еще более минимальный, в views.py:
entry = form.save()
# save uploaded file
if request.FILES['myfile']:
entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True)
Я столкнулся с подобной проблемой и решил админом сайта django.
# 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)