Нужен минимальный пример загрузки файла Django

586

Как новичок в Django, мне сложно создать приложение для загрузки в Django 1.3. Я не смог найти свежий пример/фрагменты. Может кто-нибудь отправить минимальный, но полный (модель, вид, шаблон) пример кода для этого?

  • 2
    Этот вопрос очень полезен с точки зрения документации и обучения. Зачем закрывать? ТАК иногда не дружит с новичками.
Теги:
file
upload

10 ответов

1200
Лучший ответ

У 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. Спасибо, Arthedian.

Обновление 2015-03-17: Django 1.7 поддерживается в GitHub, благодаря aronysidoro.

Обновление 2015-09-04: Django 1.8 поддерживается в GitHub благодаря nerogit. p >

Обновление 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 Управление файлами. Запомните также установить базу данных и добавить 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

Затем вам понадобится модель с файловым полем. В этом конкретном поле хранятся файлы, например. на средства массовой информации/документы/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 reference. См. Также эту дискуссию о обслуживании мультимедийных файлов.

# -*- 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}}, как в шаблоне. Подробнее об этом см. В Использование файлов в статье моделей и Документация файла 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> 

8. Инициализировать

Просто запустите syncdb и runningerver.

> cd myproject
> python manage.py syncdb
> python manage.py runserver

Результаты

Наконец, все готово. В среде разработки Django по умолчанию список загруженных документов можно увидеть на localhost:8000/list/. Сегодня файлы загружаются в/path/to/myproject/media/documents/2011/12/17/и могут быть открыты из списка.

Я надеюсь, что этот ответ поможет кому-то так же, как и мне.

  • 8
    Нашел местоположение в django docs, которое показывает загрузки файла. Пример в этом ответе превосходен, но информация в документации django будет обновляться с новыми выпусками. docs.djangoproject.com/en/dev/topics/http/file-uploads
  • 0
    @TaiwanGrapefruitTea Теперь на GitHub также есть реализация Django 1.4. Мы можем увидеть реализации для более новых версий в будущем :)
Показать ещё 20 комментариев
57

Вообще говоря, когда вы пытаетесь "просто получить рабочий пример", лучше всего "начать писать код". Здесь нет кода, чтобы помочь вам, поэтому он дает ответ на этот вопрос намного больше для нас.

Если вы хотите захватить файл, вам нужно что-то подобное в файле html где-то:

<form method="post" enctype="multipart/form-data">
    <input type="file" name="myfile" />
    <input type="submit" name="submit" value="Upload" />
</form>

Это даст вам кнопку обзора, кнопку загрузки, чтобы начать действие (отправьте форму), и обратите внимание на enctype, чтобы Django знал, чтобы дать вам request.FILES

В представлении где-нибудь вы можете получить доступ к файлу с помощью

def myview(request):
    request.FILES['myfile'] # this is my file

В файлах загрузки файлов имеется огромное количество информации.

Я рекомендую вам внимательно прочитать страницу и просто начать писать код, а затем вернуться с примерами и трассировкой стека, когда это не сработает.

  • 10
    Спасибо, Генри. На самом деле я прочитал документы и написал некоторый код, но поскольку в документах есть пробелы (например, «откуда-то импортировать handle_uploaded_file»), и мой код был ошибочным, я подумал, что было бы намного лучше, если бы я мог начать с рабочего примера ,
  • 23
    Согласитесь с qliq. Простой рабочий пример - самый эффективный способ запустить новичков, а не документы
Показать ещё 3 комментария
52

демонстрация

Обновление ответа Аксели Палена. см. репозиторий 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 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.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. Обновите view.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

  • 1
    отлично, за исключением последней строки - должно быть localhost.com:8000/upload > Это работает для django 1.6 и Python 3.3.
  • 3
    +1 за многоразовый шаблон дизайна приложения django
Показать ещё 3 комментария
22

Я должен сказать, что я нашел документацию в 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, поэтому, скорее всего, мне не хватает ключевого момента.

  • 3
    +1 за FileField и model.Form . Для начинающих (и для тривиальных задач) ручная обработка загруженных файлов, как показано выше, менее запутанна.
14

Продолжение на примере Генри:

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 из вашего представления с загруженным файловым объектом. Это сохранит файл с уникальным именем (с префиксом имени файла исходного загруженного файла) в файловой системе и вернет полный путь к сохраненному файлу. Вы можете сохранить путь в базе данных и сделать что-то с файлом позже.

  • 0
    Имран, я попробовал ваш код на моем представлении, но получил эту ошибку: объект 'WSGIRequest' не имеет атрибута 'name'.
  • 2
    Передайте объект загруженного файла ( request.FILES['myfile'] ) в handle_uploaded_file , а не сам request .
Показать ещё 2 комментария
10

Здесь это может помочь вам:  создайте поле file.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)

и также используйте это поле в своем шаблоне.

  • 0
    Это полезно, когда вам нужно вручную закалить файлы, которые вы хотите сохранить. Если это так, вам также может понадобиться этот раздел: docs.djangoproject.com/en/dev/topics/files/#the-file-object
9

Вы можете обратиться к примерам сервера в 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 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)
9

У меня также было подобное требование. Большинство примеров в сети просят создать модели и создать формы, которые я не хотел использовать. Вот мой окончательный код.

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 %}
  • 0
    хорошо, потому что иногда просто хочется использовать содержимое файла, а не сохранять загрузку ...
5

Не уверен, есть ли какие-либо недостатки этого подхода, но еще более минимальные, в views.py:

entry = form.save()

# save uploaded file
if request.FILES['myfile']:
    entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True)
0

Я столкнулся с подобной проблемой и решил сайт администратора 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)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню