博客五部曲之一 - 简单博客


1499 浏览 5 years, 11 months

28 使用FileField和ImageField上传文件

版权声明: 转载请注明出处 http://www.codingsoho.com/

FileField

我们首先用FileField来添加一个图片文件

首先在model里添加字段image为FileField。然后执行migrate,每次model有改动,都需要进行数据库migrate

class Post(models.Model):
    title = models.CharField(max_length=120)
    image = models.FileField(null=True, blank=True)
    content = models.TextField()    
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)
    timestamp = models.DateTimeField(auto_now=True, auto_now_add=False)

这个时候再打开admin,查看post,就可以看到里面多了一个字段image用来上传文件。这个时候可以开始上传文件,之前我们还需要设置一下media相关的配置,否则文件默认存放到根目录并且URL无法访问。

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR) , 'media_cdn')

跟STATIC,同样URL入口

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

再次上传文件car.jpg,文件会存放到media_cdn/car.jpg,URL为http://127.0.0.1:8000/media/car.jpg

如果要让用户上传文件,我们还需要修改一下模板和视图文件。
修改post_form.html,添加enctype以支持文件上传。

{% block content %}
<div class="row">
    <div class="col-sm-6 col-sm-offset-3">
        <h1>Form</h1>
        <form method="POST" enctype="multipart/form-data" action="">{% csrf_token %}
            {{form.as_p}}
            <input type="submit" class="btn btn-default" name="create post">
        </form>
    </div>
</div>
{% endblock content %}

修改post_create和post_update视图函数, form对象参数必须传入request.FILES

form = PostForm(request.POST or None, request.FILES or None, instance=instance)

同时,在form里加入image 字段

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = [
            'title',
            'image',
            'content'
        ]

这样用户就可以在form表单里直接添加图片了。

最后,更新一下列表和详情视图,添加图片显示, 在标题上方加入

{% if object.image %}
<img src="{{object.image.url}}" class="img-responsive">
{% endif %}

ImageField

对于图片处理,Django有另外一个Field:ImageField,提供了更强大的功能。

https://docs.djangoproject.com/en/1.11/ref/models/fields/

要支持ImageField,需要安装依赖库 Pillow

首先修改image字段为ImageField,同时添加另外两个字段height_field和width_field

class Post(models.Model):
    title = models.CharField(max_length=120)
    image = models.ImageField(null=True, blank=True, width_field="width_field", height_field="height_field")
    height_field = models.IntegerField(default=0)
    width_field = models.IntegerField(default=0)
    content = models.TextField()    
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)
    timestamp = models.DateTimeField(auto_now=True, auto_now_add=False)

修改之后记得执行makemigrations和migrate

再次从admin打开post,可以看到heigh_field和with_field自动填进了当前图片的高度和宽度值。
新创建的图片也会自动填进这两个值,目前我们还不打算去用这两个值,但是在很多场合它们会非常有用处。

最后,我们通过函数自定义图片的上传路径

def upload_location(instance, filename):
    return "%s/%s" % (instance.id, filename)

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=120)
    image = models.ImageField(null=True, blank=True, width_field="width_field", height_field="height_field", upload_to=upload_location)

新的上传路径中,将会首先根据实例ID建一个目录,然后把图片放在下面。我们也可以修改图片的名字等,这个可以根据你的要求进行操作。