Need a minimal Django file upload example
作为一个刚加入django的新手,我在django 1.3上制作上传应用程序时遇到了困难。我找不到任何最新的示例/片段。是否可以发布一个最小但完整的(模型、视图、模板)示例代码?
phew,django文档确实没有很好的例子。我花了2个多小时去挖掘所有的碎片,以了解这是如何工作的。有了这些知识,我实现了一个项目,可以上传文件并将其显示为列表。要下载项目的源代码,请访问https://github.com/axelpale/minimal-django-file-upload-example或克隆:
1 | > git clone https://github.com/axelpale/minimal-django-file-upload-example.git |
更新2013-01-30:Github的源代码除了1.3外,还实现了django 1.4。尽管更改很少,以下教程对1.4也很有用。
更新2013-05-10:Github Django 1.5的实施。urls.py中的重定向和list.html中的url template标记的使用发生了细微变化。感谢Hubert3的努力。
更新2013-12-07:Github支持Django 1.6。myapp/urls.py中的一个导入已更改。感谢亚瑟王。
更新2015-03-17:Github支持Django 1.7,感谢Aronysidoro。
更新2015-09-04:Github支持Django 1.8,感谢Nerogit。
更新2016-07-03:Github支持Django 1.9,感谢Daavve和Nerogit
项目树一个基本的django 1.3项目,带有用于上传的单个应用程序和媒体/目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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存储上传文件的位置以及django为其提供的URL。默认情况下,media_root和media_url位于settings.py中,但它们为空。有关详细信息,请参见Django管理文件中的第一行。记住,还要设置数据库并将myapp添加到已安装的应用程序中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ... 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/中。请参见文件字段参考。
1 2 3 4 5 | # -*- coding: utf-8 -*- from django.db import models class Document(models.Model): docfile = models.FileField(upload_to='documents/%Y/%m/%d') |
三。表单:myproject/myapp/forms.py
要处理好上传,您需要一个表单。此窗体只有一个字段,但这已足够。有关详细信息,请参阅表单文件字段参考。
1 2 3 4 5 6 7 8 | # -*- 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
所有魔法发生的地方。注意如何处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # -*- 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不提供媒体根目录。这在生产环境中是危险的。但在发展阶段,我们可以缩短。注意最后一行。这一行使Django能够提供来自媒体URL的文件。这只在开发阶段有效。
有关详细信息,请参阅django.conf.urls.static.static reference。另请参见有关提供媒体文件的讨论。
1 2 3 4 5 6 7 8 | # -*- 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。这里没什么特别的。
1 2 3 4 5 6 | # -*- 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",将method设置为"post",才能上载到django。有关详细信息,请参阅文件上载文档。
filefield有许多可以在模板中使用的属性。例如,document.docfile.url和document.docfile.name如模板中所示。请参阅使用模型中的文件一文和文件对象文档中关于这些内容的更多信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <!DOCTYPE html> <html> <head> <meta charset="utf-8"> Minimal Django File Upload Example </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。初始化
只需运行syncdb和runserver。
1 2 3 | > cd myproject > python manage.py syncdb > python manage.py runserver |
结果
最后,一切都准备好了。在默认的django开发环境中,可以在
我希望这个答案能像帮助我一样帮助别人。
一般来说,当你试图"得到一个有效的例子"时,最好是"开始编写代码"。这里没有代码可以帮助您,因此回答这个问题对我们来说更有用。
如果你想抓取一个文件,你需要在一个HTML文件中的某个地方这样做:
1 2 3 4 | <form method="post" enctype="multipart/form-data"> <input type="file" name="myfile" /> <input type="submit" name="submit" value="Upload" /> </form> |
这将给你一个浏览按钮,一个上传按钮来启动操作(提交表单),并记录下EncType,以便Django知道给你一个
在某个视图中,您可以使用
1 2 | def myview(request): request.FILES['myfile'] # this is my file |
文件上传文档中有大量信息
我建议您彻底阅读该页,然后开始编写代码,然后在它不起作用时返回示例和堆栈跟踪。
演示
更新Akseli Pal_n的答案。参见Github回购协议,与Django 2合作
最小Django文件上载示例1。创建Django项目运行StartProject::
1 | $ django-admin.py startproject sample |
现在创建一个文件夹(示例)::
1 2 3 4 5 6 7 | sample/ manage.py sample/ __init__.py settings.py urls.py wsgi.py |
2。创建一个应用程序
创建一个应用程序:
1 2 | $ cd sample $ python manage.py startapp uploader |
现在将创建包含这些文件的文件夹(
1 2 3 4 5 6 7 8 9 | uploader/ __init__.py admin.py app.py models.py tests.py views.py migrations/ __init__.py |
三。更新设置.py
在
1 2 3 4 5 6 7 | INSTALLED_APPS = [ ...<other apps>... 'uploader.apps.UploaderConfig', ] MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/' |
4。更新URLS.Py
在
1 2 3 4 5 6 7 8 9 | ...<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
更新
1 2 3 4 5 6 7 8 9 10 11 12 | 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。更新视图
更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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。创建模板
在文件夹上载程序中创建文件夹模板,然后创建文件home.html,即
1 2 3 4 5 6 7 8 9 | picture <form action="#" method="post" enctype="multipart/form-data"> {% csrf_token %} {{form}} <input type="submit" value="Upload" /> </form> {% for img in images %} {{forloop.counter}}.{{ img.pic.name }} ({{img.upload_date}})<hr /> {% endfor %} |
8。同步数据库
同步数据库和运行服务器:
1 2 3 | $ python manage.py makemigrations $ python manage.py migrate $ python manage.py runserver |
访问http://localhost.com:8000
我必须说,我发现Django的文档令人困惑。还有一个最简单的例子,为什么要提到表格?我在views.py中工作的例子是:
1 2 3 4 5 6 7 8 9 | 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文件看起来像下面的代码,尽管本例只上载一个文件,而保存文件的代码处理了许多:
1 2 3 4 5 6 | <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> |
这些示例不是我的代码,它们是从我发现的另外两个示例中选择的。我是姜戈的一个相对初学者,所以很可能我错过了一些要点。
延伸到亨利的例子:
1 2 3 4 5 6 7 8 9 10 | 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 |
您可以使用上载的文件对象从视图中调用这个
我也有类似的要求。网络上的大多数例子都要求创建模型并创建我不想使用的表单。这是我的最终代码。
1 2 3 4 5 | if request.method == 'POST': file1 = request.FILES['file'] contentOfFile = file1.read() if file1: return render(request, 'blogapp/Statistics.html', {'file': file1, 'contentOfFile': contentOfFile}) |
在上传的HTML中,我写道:
1 2 3 4 5 6 7 8 | {% block content %} File content <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:
1 2 3 4 5 | {% block content %} File uploaded successfully {{file.name}} </br>content = {{contentOfFile}} {% endblock %} |
在这里,它可以帮助您:在models.py中创建一个文件字段
上传文件(在admin.py中):
1 2 3 4 5 6 7 8 9 10 | 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/fineuloader/server-examples/tree/master/python/django-fine-uploader
它非常优雅,最重要的是,它提供了特色的JSlib。模板不包括在服务器示例中,但您可以在其网站上找到演示。精细上传器:http://fineuloader.com/demos.html
Django优质上传机VIEW
uploadView向各自的处理程序发送post和delete请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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' })) |
表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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中更是如此:
1 2 3 4 5 | entry = form.save() # save uploaded file if request.FILES['myfile']: entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True) |
我也遇到了类似的问题,由django管理网站解决。
1 2 3 4 5 6 7 8 9 10 11 12 | # 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) |