Відповіді:
Phew, 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. Дякуємо Артедіану .
Оновлення 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
Щоб завантажувати та обслуговувати файли, потрібно вказати, де 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',
)
Далі вам потрібна модель з FileField. Це конкретне поле зберігає файли, наприклад, у засобах масової інформації / документах / 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')
Щоб красиво здійснити завантаження, вам потрібна форма. Ця форма містить лише одне поле, але цього достатньо. Докладніше див. Посилання на FileField форми .
# -*- coding: utf-8 -*-
from django import forms
class DocumentForm(forms.Form):
docfile = forms.FileField(
label='Select a file',
help_text='max. 42 megabytes'
)
Погляд, де відбувається вся магія. Зверніть увагу, як request.FILES
поводитися. Для мене було дуже важко помітити той факт, який request.FILES['docfile']
можна зберегти в моделях.FileField просто так. Збереження () моделі обробляє збереження файлу у файловій системі автоматично.
# -*- 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)
)
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)
Щоб зробити перегляд доступним, потрібно вказати для нього URL-адреси. Тут нічого особливого.
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views',
url(r'^list/$', 'list', name='list'),
)
Остання частина: шаблон для списку та форма для завантаження під ним. Форма повинна мати атрибут enctype-атрибут "multipart / form-data" та метод "post", щоб зробити завантаження на Django можливим. Докладніше див. Документацію щодо завантаження файлів .
У FileField є багато атрибутів, які можна використовувати в шаблонах. Наприклад, {{document.docfile.url}} та {{document.docfile.name}}, як у шаблоні. Детальніше про них див. У статті Використання файлів у моделях та Документація об'єкта File .
<!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>
Просто запустіть syncdb та runserver.
> cd myproject
> python manage.py syncdb
> python manage.py runserver
Нарешті, все готово. За умовчанням середовище розробки Django список завантажених документів можна побачити на localhost:8000/list/
. Сьогодні файли завантажуються в / шлях / до / мій проект / медіа / документи / 2011/12/17 / і можуть бути відкриті зі списку.
Я сподіваюся, що ця відповідь комусь допоможе настільки, наскільки це допомогло б мені.
{% url list %}
стає {% url "list" %}
.
Взагалі кажучи, коли ви намагаєтеся "просто отримати робочий приклад", найкраще "просто почати писати код". Тут немає коду, який би вам допоміг, тому для відповіді на це питання нам набагато більше працювати.
Якщо ви хочете схопити файл, вам потрібно щось подібне у файлі html десь:
<form method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" name="submit" value="Upload" />
</form>
Це дасть вам кнопку перегляду, кнопку завантаження, щоб розпочати дію (надішліть форму) та відзначте ентетип, щоб Джанго знав, щоб дати вам request.FILES
У вікні десь ви можете отримати доступ до файлу за допомогою
def myview(request):
request.FILES['myfile'] # this is my file
У документах про завантаження файлів є величезна кількість інформації
Я рекомендую вам уважно прочитати сторінку та просто почати писати код - потім повернутися із прикладами та скласти сліди, коли вона не працює.
enctype="multipart/form-data"
, Що мені потрібно , щоб зробити цю роботу, спасибі!
Дивіться github repo , працює з Django 3
Запустити стартовий проект ::
$ django-admin.py startproject sample
тепер створена папка ( зразок ).
Створіть додаток ::
$ cd sample
$ python manage.py startapp uploader
Тепер створена папка ( uploader
) з цими файлами:
uploader/
__init__.py
admin.py
app.py
models.py
tests.py
views.py
migrations/
__init__.py
На sample/settings.py
оних 'uploader'
до INSTALLED_APPS
і додати MEDIA_ROOT
і MEDIA_URL
, тобто ::
INSTALLED_APPS = [
'uploader',
...<other apps>...
]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
в 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.UploadView.as_view(), name='fileupload'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
оновлення uploader/models.py
::
from django.db import models
class Upload(models.Model):
upload_file = models.FileField()
upload_date = models.DateTimeField(auto_now_add =True)
оновлення 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
Створіть зразок папки / завантажувача / шаблонів / завантажувача
Створіть файл upload_form.html, тобто 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>
<a href="{{ document.upload_file.url }}">{{ document.upload_file.name }}</a>
<small>({{ document.upload_file.size|filesizeformat }}) - {{document.upload_date}}</small>
</li>
{% endfor %}
</ul>
</div>
Синхронізувати базу даних та пробіг ::
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver
відвідайте http: // localhost: 8000 /
FileField
час використовував верхівку ImageField
, чи могла б хто-небудь пояснити вибір?
FileField
. ImageField
Потрібно лише завантажувати зображення. оновлення працюватиме з Django 1.11.
Треба сказати, що я вважаю документацію на джанго заплутаною. Також для найпростішого прикладу, чому згадуються форми? Приклад, з яким я працював у 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>
Ці приклади не є моїм кодом, вони отримані з двох інших прикладів, які я знайшов. Я відносно початківця джанго, тому дуже ймовірно, що я пропускаю якийсь ключовий момент.
FileField
і a model.Form
. Для початківців (і для тривіальних завдань) ручна обробка завантажених файлів, як показано вище, менш заплутана.
У мене також була схожа вимога. Більшість прикладів у мережі пропонують створити моделі та створити форми, які я не хотів використовувати. Ось мій підсумковий код.
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
функцію зі свого подання із завантаженим файловим об’єктом. Це дозволить зберегти файл з унікальним іменем (з префіксом імені оригіналу завантаженого файлу) у файловій системі та повернути повний шлях збереженого файлу. Ви можете зберегти шлях у базі даних і пізніше зробити щось із файлом.
request.FILES['myfile']
) handle_uploaded_file
, а не request
сам.
prefix=source.name
його, додали зайві символи в кінці файлу, псуючи розширення файлу. Наприклад, upload.csv
змінили на upload.csv5334
. Змінивши його, щоб suffix=source.name
виправити це для мене.
Тут це може допомогти вам: створити поле файлу у вашому 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. Шаблон не включений у приклади сервера, але ви можете знайти демонстрацію на його веб-сайті. Тонкий завантажувач: 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'
}))
form.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)
Я зіткнувся з подібною проблемою і вирішив сайт адміністратора 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)