django 搭建上传文件系统——细说Form Validation(二)

我学习django的主要途径是http://djangobook.com, 作者的书好像也出版了。作者的思路很清爽,讲解浅显易懂,该深入的地方深入,我很喜欢,比django官方文档感觉好多了,官方文档讲解的太晦涩。这些随笔是结合一些例子来细说django的学习要点与本人的学习心得。

有些中文博客也讲解了用django做一些小的项目,但是没有细讲django的原理,即为什么要这样做,我就个人的理解会细致地讲解各个部分的知识点。希望能帮助更多人,也希望与更多人一起进步。

本人配置环境:(2017.6.20)

注意: 在windows中的文件系统是用反斜杠'\'来表示,但是即使是在windows系统下的django,在表示文件路径时依然用unix 风格的斜杠'/'

OS: win7

python:3.6.2

Django: 1.11.2


创建项目与应用

 

每个项目的前部分:创建项目与应用,把应用添加到settings.py 的'INSTALLED_APP'里,在settings.py里设置默认的数据库,并同步数据库数据的操作都是一样的,就不具体叙述,可以参考我前面的例子。

我把这个上传文件的项目命名为disk, 项目名称为mysite,创建完成后的结构如下:(disk/templates, disk/uploads, disk/forms.py 是我本人创建的,不是系统创建的。请忽略除mysite, disk以外的部分,与此例无关。)

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'disk',
)

 

创建Form类实例

 

为了简单起见,在这个文件上传系统中,我们只设计两个变量:上传文件的用户改名,及上传的文件。Django中为用户定义了一个django.forms库,这个库可以方便地进行form类的数据显示及数据验证,省去了很多用户的代码。django.forms库用起来也方便,只需要在HTML文件中需要增加<form> tag时,定义相应的 Form 类就可以。在以下的示例中我们最终的页面上只有一个<form> tag, 所以我们只需要定义一个Form类即可。Django 社区的惯例是把Form类单独放在一个forms.py文件中,我们最好也遵循这个规则。创建disk\forms.py文件,并写入:

# mysite\disk\forms.py

from django import forms

class UserForm(forms.Form):
    userName = forms.CharField(max_length = 20)
    uploadFile = forms.FileField()

可以看出Form类的语法与定义Model时的语法很像,对于每个变量都要定义它的域的属性,这个我在下面的Model章节中会仔细再讲。在UserForm中,我们定义了userName,它是字符属性,还定义了uploadFile,它是文件属性。默认情况下这两个变量都是不能为空的,如果为空,则会在html页面中显示出相应的错误。

 

创建Models(数据库层)

 

我们需要把用户名和上传的文件路径放到数据库中, 所以在设计数据库时需要两个字段:userName and uploadFile。在disk\models.py文件中写入:

# disk\models.py

from django.db import models

# Create your models here.
class User(models.Model):
    userName = models.CharField(max_length = 30)
    uploadFile = models.FileField(upload_to = 'disk/upload/')

    def __str__(self):
        return self.userName

对于models的定义,要讲的东西很多。

  • 每个变量都要定义成某种类型的域(field),django会根据不同的域来决定某些事情。比如,域的类型会决定数据库中该变量的数据类型(比如INTERGER, VARCHAR)。对于每个变量,在html显示层,django把它定义成一个单独的widget。最终是以什么widget显示变量也是与该域的类型有关的,比如一个CharField变量最终会以<input type= 'text'>的形式显现。
  • 以下是每种域类型变量的定义,来自http://www.djangobook.com/model-definition-reference/。为了保证释义的完整性与准确性,我就不翻译成中文了:

 

下张表是所有域通用的可选参数:

  • FileFiled 说明:此类变量不支持primary_key, unique参数(见上表)。有两个可选参数:upload_tostorage'upload_to'定义的是一个本地的文件路径,这个路径可以是个相对路径,它会自动加到settings.py文件中 BASE_DIR 目录的后面。一般情况下,即使文件上传成功也不会保存到数据库中,除非显性的调用save()函数。从性能上考虑,不会把上传的文件存储到数据库中,而是把文件的路径存储到数据库中(如果调用了save()函数)。
  • 在定义完models后,要把它同步到数据库中,主要用两个命令python manage.py makemigrations,   python manage.py migrate

 

创建Views (逻辑层)

 

视图views决定的是按照怎样的逻辑收集处理数据,并把用户的数据呈现给用户;可以把它理解成用户数据(数据库)到最终呈现页面(web页面)的中间人。这部分一般就是纯粹的python代码。打开mysite\disk\views.py文件并写入:

# mysite\disk\views.py

from django.shortcuts import render
from disk.forms import UserForm
from disk.models import User


def uploads(request):
    if request.method == 'POST':
        userform = UserForm(request.POST, request.FILES)
        if userform.isValid():
              user = User()
              user.userName = userform.cleaned_data['userName']
              user.uploadFile = userform.cleaned_data['uploadFile']
              user.save()
              return render(request, 'uploadOK.html')
    else:
        userform = UserForm(initial ={'userName': 'sunshore'})
    return render(request, 'upload.html', {'userform': userform})

 views.py文件就把上文定义的UserForm和User (models文件)引用了过来。

  • 对于HttpRequest.POST对象,我们在上一节中讲过,这里不再叙述。
  • HttpRequest.FILES对象也是一个“类字典”对象,它的'key'是文件名,与html文件中<input type = "file" name = "" />中的内容相同;'key'所对应的'value' 是上传的文件。注意: 这个对象必须是在HttpRequest method = 'POST' 并且<form> tag中包含 enctype="multipart/form-data"时才会有值,否则会返回一个空的类字典对象。
  • django中Form类实例化后,可以通过isValid()函数来检查数据是否有效;如果有效,则该实例就会有cleaned_data属性,这是一个字典对象,包含的是Form类数据。
  • 我们首先检查HttpRequest是一个POST 方法,然后实例化Form类,如果实例化成功,就把数据存储到数据库中去。(当然最终存储到数据库中不是文件本身,而是文件路径,上部分提到过)。如果HttpRequest不是POST方法,则把用户名初始化成'sunshore'

 

创建Templates(显示层)

 

我们需要创建templates来定制数据的显示。Django中将数据的处理与显示分开了,数据的处理是在views.py中,数据的显示是在templates里。 默认情况下,mysite/mysite/settings.py文件中的TEMPLATES定义'APP_DIRS' = True, 也就是说django会到各个应用的文件下寻找templates文件夹,使用里面定义的html文件。

我们需要在mysite/disk/templates创建两个html文件:upload.htmluploadOK.html,并写入:

# mysite\disk\templates\upload.html

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>

<style type="text/css">

     ul.errorlist{
     margin:0;
     padding:0;
    }
    .errorlist li{
    background-color: blue;
    color: white;
    display: block;
    font-size: 1.0em;
    margin: 0 0 1px;
    padding: 0 10px;
   }
</style>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Upload File</title>
</head>
<body>
     <h1>User Upload Files</h1>
     <form action="" method="post" enctype="multipart/form-data" >
      {{userform.as_p}}
      {% csrf_token %}
      <input type="submit" value="ok"/>
     </form>
</body>
</html>
# mysite\disk\templates\uploadOK.html

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Upload OK</title>
</head>
<body>
         <p > Uploading Files Successfully </p>
         <a href= 'upload'>Back to upload file page </a>

</body>
</html>
  •  Form类会自动生成页面的错误信息,并以errorlist的形式返回结果。在html文件中我们可以对errorlist进行CSS的定制,使得error信息更为突出。这就是<style> ....</style>那段代码的作用。
  • 默认情况下,Form类显示成员的排版格式有form.as_p, form.as_table, form.as_ul这三种形式,不同形式下成员的排列是不同的。比如本示例中userform.as_p会显示如下

userform.as_table 显示结果:

 

userform.as_ul 显示结果:

我们可以根据自己的喜好来选择成员的显示形式。当然django也支持自己定制所有成员的显示形式。感兴趣的读者可以参考:http://djangobook.com/tying-forms-views.

 

设置urlconf 文件

 

这个是用正则表达式的方式定义了HttpRequest.url和views的对应关系。在mysite\urls.py文件中输入:

# mysite\urls.py

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

from disk import views as disk_views

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'mysite2.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),

    url(r'^admin/', include(admin.site.urls)),
    url(r'^upload/$', disk_views.upload),
)

 

启动服务

 

mysite文件夹下,终端命令行输入: python manage.py runserver 80

 

在用户正确地上传了文件后,我们可以在mysite\disk\upload文件夹下看到此文件,这个是在models.py里定义的,读者们可以试一下。

posted @ 2017-06-20 18:32  sun sun  阅读(1960)  评论(0编辑  收藏  举报