对于Web应用程序,以便能够上传文件(资料图片,歌曲,PDF格式,文字……),它通常是很有用的。下面来看看如何使用Django上传图片。在开始开发图片上传之前,请确保Python的图像库(PIL)已经安装。现在来说明上传图片,我们这里使用Django form结合models的形式上传图片,实现以下几个功能:
- Model和ModelForm创建表单
- POST上传图片
一、使用ModelForm上传图片
- 编写Models
首先创建Model,保存上传资料:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# ./polls/models.py from django.db import models from django.utils import timezone class UploadedImageModel(models.Model): STATUS_SIZES = ( (0, '进行中'), (1, '已完成'), ) name = models.CharField('名称', max_length=10) create_date = models.DateTimeField("时间", default=timezone.now()) note = models.CharField('备注', max_length=200, blank=True) image = models.ImageField('图片', upload_to='photos', blank=False) operator = models.CharField('作者', max_length=50, blank=True) status = models.IntegerField('状态', default=0, choices=STATUS_SIZES) # 0进行中,1已完成 class Meta: db_table = "uploadedimage" def __str__(self): return self.name |
正如你所看到的,这里的主要区别仅仅是models.ImageField。ImageField字段将确保上传的文件是一个图像。如果不是,格式验证将失败。ImageField使用强制性参数upload_to,这表示硬盘驱动器,图像保存所在的地方。注意,该参数将被添加到settings.py文件中定义的MEDIA_ROOT选项中。
1 |
MEDIA_ROOT = '/tmp' |
model中定义的image的参数upload_to=’photos’,上传的图片将保存至/tmp/photos/目录下。
然后记得要migrate数据库:
1 2 |
$ python manage.py makemigrations polls $ python manage.py migrate |
- 编写Forms
接着建立表单,我们这里使用ModelForm,使模型跟表单紧密关联。
1 2 3 4 5 6 7 8 9 10 11 |
# ./polls/forms.py from django import forms from django.utils.timezone import now from .models import UploadedImage class UploadedImageForm(forms.ModelForm): class Meta: model = UploadedImageModel fields = '__all__' #fields = ['name','create_date','note','image','operator','status'] |
- 编写Views
现在我们有表单和模型,让我们来创建视图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# ./polls/views.py from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect from .forms import UploadedImageForm from .models import UploadedImageModel def UploadedImageView(request): if request.method == "POST": form = UploadedImageForm(request.POST, request.FILES) if form.is_valid(): photo = form.save() print(photo.image.url) return HttpResponseRedirect('/polls/success/') else: form = UploadedImageForm() return render(request, 'polls/upload.html', {'form': form}) def success(request): return render(request, 'polls/success.html') |
视图逻辑大概的意思可以参考:Django上传下载文件
- 编写urls
url分为两个部分,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# ./mysite/urls.py from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^polls/', include('blog.urls')), url(r'^admin/', admin.site.urls), ] # ./polls/urls.py from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.UploadedImageView), url(r'^success/$', views.success), ] |
- 编写templates
views.py中需要的两个html文件放在mysite/templates/polls/目录下。Form要支持上传图片,需要在form中设置enctype=”multipart/form-data”,不设置的话文件不支持上传。
upload.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>UploadImage</title> </head> <body> {% if form.errors %} <p style="color: red;"> Please correct the error{{ form.errors|pluralize }} below. </p> {% endif %} <form method="post" action="" enctype="multipart/form-data"> <table> {% csrf_token %} {{ form }} </table> <input type="submit" value="upload"/> </form> </body> </html> |
success.html
1 2 3 4 5 6 7 8 9 10 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Success!</title> </head> <body> <div>Success!</div> </body> </html> |
到此为止代码都完成了,只需要开启Django server即可。
- 上传测试
正常情况下,访问http://127.0.0.1:8000/polls/可以看见如下页面:
上传成功后可以在/tmp/photos目录下看见图片,并且在数据库中可以查看到相关信息,其中就包括了图片路径。
二、使用Form类上传图片
上面创建表单是一种比较简洁的方式,直接使用Django提供的ModelForm类;如果不想所有字段保存到数据库,可以使用Form类,属于另一种方式:
- 编写Forms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from django import forms from django.utils.timezone import now from .models import UploadedImageModel class UploadedImageForm(forms.Form): STATUS_SIZES = ( (0, '进行中'), (1, '已完成'), ) name = forms.CharField(label="名称") create_date = forms.DateTimeField(label="时间", initial=now()) note = forms.CharField(label="备注", required=False) image = forms.ImageField(label="图片") operator = forms.CharField(label="作者") status = forms.IntegerField(label="状态", widget=forms.Select(choices=STATUS_SIZES),) |
- 编写Views
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 |
from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect from .forms import UploadedImageForm from .models import UploadedImageModel def UploadedImageView(request): if request.method == "POST": form = UploadedImageForm(request.POST, request.FILES) if form.is_valid(): photo = UploadedImageModel.objects.create( name = form.cleaned_data['name'], create_date = form.cleaned_data['create_date'], note=form.cleaned_data['note'], image=form.cleaned_data['image'], operator=form.cleaned_data['operator'], status=form.cleaned_data['status'], ) photo.save() print(photo.image.url) return HttpResponseRedirect('/polls/success/') else: form = UploadedImageForm() return render(request, 'polls/upload.html', {'form': form}) def success(request): return render(request, 'polls/success.html') |
整个例子对于处理文件上传也是一样的,只需要改变一些数据类型即可。
另外整个例子涉及的Django基础知识还是挺多,比如views、urls、models、templates、forms、modelform等;这里都没细说,可以看Django官网。
三、通过API上传图片
可以通过Django REST framework框架编写API,然后可以通过API来上传图片。
首先需要配置Django静态目录,然后把文件上传到静态目录,不然应该不能直接访问到图片。
修改settings文件,记得注释MEDIA_ROOT配置。
1 2 3 4 5 |
# ./settings STATIC_URL = '/static/' STATICFILES_DIRS=[ os.path.join(BASE_DIR,'static') ] |
然后对于model的配置就要把图片上传到静态目录了,配置应该如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# ./polls/models.py from django.db import models from django.utils import timezone class UploadedImageModel(models.Model): STATUS_SIZES = ( (0, '进行中'), (1, '已完成'), ) name = models.CharField('名称', max_length=10) create_date = models.DateTimeField("时间", default=timezone.now()) note = models.CharField('备注', max_length=200, blank=True) image = models.ImageField('图片', upload_to='static/images/%Y/%m/%d', blank=False) operator = models.CharField('作者', max_length=50, blank=True) status = models.IntegerField('状态', default=0, choices=STATUS_SIZES) # 0进行中,1已完成 class Meta: db_table = "uploadedimage" def __str__(self): return self.name |
下面就是添加djangoframework相关配置了,首先要安装Djangoframework,具体看:Django REST framework快速入门。
首先在polls应用下创建一个api目录,然后编写serializers.py文件:
1 2 3 4 5 6 7 8 9 10 |
# ./polls/api/serializers.py from rest_framework.serializers import ModelSerializer from rest_framework import serializers from polls.models import UploadedImageModel class UploadImageSerializer(ModelSerializer): class Meta: model = UploadedImageModel fields = ('name','note','image','operator','status') |
然后提供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 |
# ./polls/api/views.py from rest_framework import viewsets from rest_framework.response import Response from rest_framework import status from polls.api.serializers import UploadImageSerializer from polls.models import UploadedImageModel class UploadImageViewSet(viewsets.ModelViewSet): """ upload image """ def create(self, request, *args, **kwargs): self.serializer_class = UploadImageSerializer file = request.data.dict() # file['image'] = request.FILES.get('image') serial = UploadImageSerializer(data=file) if not serial.is_valid(): return Response(status=status.HTTP_400_BAD_REQUEST) serial.save() return Response(serial.data) def list(self, request, *args, **kwargs): self.serializer_class = UploadImageSerializer self.queryset = UploadedImageModel.objects.all() return super(UploadImageViewSet, self).list(request) |
最后添加一些urls路由,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# ./polls/urls.py from django.conf.urls import url, include from rest_framework import routers from . import views from polls.api.views import * router = routers.DefaultRouter(trailing_slash=True) router.register(r'', UploadImageViewSet, base_name='UploadFile') urlpatterns = [ url(r'^api/', include(router.urls)), url(r'^$/', views.UploadedImageView), url(r'^success/$', views.success), ] |
都完成之后,就可以通过http://127.0.0.1:8000/polls/api/接口进行访问,上传图片了。
然后也可以通过curl命令上传,其格式如下:
1 2 3 4 5 6 7 8 |
$ curl --request POST \ --header 'content-type: multipart/form-data' \ --form image=@/tmp/1.png \ --form name=dkey \ --form note=upload \ --form operator=admin \ --form status=1 --url http://127.0.0.1:8000/polls/api/ |
<参考>
http://www.imooc.com/article/20932
http://www.jianshu.com/p/32e5abda158f