Django进阶

一、Form

django中的Form一般有两种功能:1、输入html  2、验证用户输入

1、输入html

from django.shortcuts import render
from django import forms

class UserForm(forms.Form):
    host = forms.CharField()
    port = forms.CharField()
    email = forms.EmailField()
    mobile = forms.CharField()


def user_list(request):
    obj = UserForm()
    return render(request,"index.html",{"obj":obj})

  html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/app01/user_list/">
        <!--自动生成input标签-->
        <p>主机:{{ obj.host }}</p>
        <p>端口:{{ obj.port }}</p>
        <p>邮箱:{{ obj.email }}</p>
        <p>手机:{{ obj.mobile }}</p>
        <input type="submit">
    </form>
</body>
</html>

 

2、验证

from django.shortcuts import render
from django import forms

class UserForm(forms.Form):
    host = forms.CharField()
    port = forms.CharField()
    email = forms.EmailField()
    mobile = forms.CharField()

def user_list(request):
    obj = UserForm()
    if request.method == "POST":
        user_input_obj = UserForm(request.POST)#把提交过来的数据封装到UserForm,UserForm会自动把数据封装到user_input_obj
        if user_input_obj.is_valid():   #验证用户输入是否合法
            data = user_input_obj.clean()   #合法,获取数据
        else:
            error_msg = user_input_obj.errors   #不合法,返回错误信息
            return render(request,"index.html",{"obj":user_input_obj,"error":error_msg})
    return render(request,"index.html",{"obj":obj})

优化

def user_list(request):
    obj = UserForm(request.POST)#如果有数据,把提交过来的数据封装到UserForm,UserForm会自动把数据封装到user_input_obj
    if request.method == "POST":
        if obj.is_valid():   #验证用户输入是否合法
            data = obj.clean()   #合法,获取数据
        else:
            error_msg = obj.errors.as_data()   #不合法,返回错误信息
            return render(request,"index.html",{"obj":obj,"error":error_msg})
    return render(request,"index.html",{"obj":obj,})
View Code

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/app01/user_list/" method="post">
        <!--自动生成input标签-->
        <p>主机:{{ obj.host }}<span>{{ error.host }}</span></p>
        <p>端口:{{ obj.port }}<span>{{ error.port }}</span></p>
        <p>邮箱:{{ obj.email }}<span>{{ error.email }}</span></p>
        <p>手机:{{ obj.mobile }}<span>{{ error.mobile }}</span></p>
        <input type="submit">
    </form>
</body>
</html>
View Code

 

3、定制From表单

(1)设置报错信息,添加属性样式

class UserForm(forms.Form):
    host = forms.CharField(error_messages={"required":"主机不能为空"},#设置显示的错误信息
                           widget=forms.TextInput(attrs={"class":"form-control",
                                                         "placeholder": "主机"})#添加属性和样式
                           )
    port = forms.CharField()
    email = forms.EmailField()
    mobile = forms.CharField()

(2)多行文本框

#多行文本框,备注
    memo = forms.CharField(required=False,  #可以为空
                           widget=forms.Textarea(attrs={"class":"form-control",
                                                         "placeholder": "备注"})#添加属性和样式
                           )

(3)下拉框

#下拉框
    user_type_choice=(
        (0,"普通用户"),
        (1,"高级用户")
    )
    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                  attrs={'class': "form-control"}))

(4)动态生成select标签

文件中取数据

#动态下拉框
   u_type = forms.IntegerField(widget=forms.widgets.Select( attrs={'class': "form-control"}))

    def __init__(self, *args, **kwargs):
        super(UserForm, self).__init__(*args, **kwargs)
        import json
        f=open("u_type_db")
        data = f.read()
        data_tuple = json.loads(data)
        self.fields['u_type'].widget.choices = data_tuple
#u_type_db
[[0, "AAA"], [1, "BBB"],[2,"CCC"]]

 数据库中取数据

def __init__(self, *args, **kwargs):
    super(UserForm, self).__init__(*args, **kwargs)
    data_tuple=models.UserInfo.objects.all().values_list('id','username')
    self.fields['u_type'].widget.choices = data_tuple

 

(5)自定义验证条件

#自定义验证
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')


class UserForm(forms.Form):
    mobile = forms.CharField(validators=[mobile_validate, ])#添加自定义手机号验证

4、漂亮显示错误信息

def user_list(request):
    obj = UserForm()
    if request.method == "POST":
        user_input_obj = UserForm(request.POST)#把提交过来的数据封装到UserForm,UserForm会自动把数据封装到user_input_obj
        if user_input_obj.is_valid():   #验证用户输入是否合法
            data = user_input_obj.clean()   #合法,获取数据
        else:
            error_msg = user_input_obj.errors   #不合法,返回错误信息
            return render(request,"index.html",{"obj":user_input_obj,"error":error_msg})
    return render(request,"index.html",{"obj":obj,})

默认显示ul样式as_ul(),不美观

error_msg = user_input_obj.errors   #不合法,返回错误信息

 

改成as_data()后只显示一个字符串格式

error_msg = user_input_obj.errors.as_data()   #不合法,返回错误信息

方法:

  定义

  在html顶部调用

{% load  form_tag %}

  引用

<p>主机:{{ obj.host }}<span>{% error_message error.host %}</span></p>

 

as_json()  用于ajax返回

error_msg = user_input_obj.errors.as_json()#不合法,返回错误信息
return HttpResponse(error_msg )

 

实例:

html

{% load  form_tag %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/app01/user_list/" method="post">
        <!--自动生成input标签,也可以自己写html标签-->
        <p>主机:{{ obj.host }}<span>{% error_message error.host %}</span></p><!--引用-->
        <p>端口:{{ obj.port }}<span>{{ error.port }}</span></p>
        <p>邮箱:{{ obj.email }}<span>{{ error.email }}</span></p>
        <p>手机:{{ obj.mobile }}<span>{{ error.mobile }}</span></p>
        <p>备注:{{ obj.memo }}<span>{{ error.memo }}</span></p>
        <p>用户类型:{{ obj.user_type }}<span>{{ error.user_type }}</span></p>
        <input type="submit">
    </form>
</body>
</html>
View Code

views

from django.shortcuts import render
from django import forms
import re
from django.core.exceptions import ValidationError

#自定义验证
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')

class UserForm(forms.Form):
    host = forms.CharField(error_messages={"required":"主机不能为空"},#设置显示的错误信息
                           widget=forms.TextInput(attrs={"class":"form-control",
                                                         "placeholder": "主机"})#添加属性和样式
                           )
    port = forms.CharField(error_messages={"required":"端口不能为空"})
    email = forms.EmailField(error_messages={"required":"邮箱不能为空"})
    mobile = forms.CharField(error_messages={"required":"手机不能为空"},
                             validators=[mobile_validate, ])#添加自定义验证

    #多行文本框,备注
    memo = forms.CharField(required=False,  #可以为空
                           widget=forms.Textarea(attrs={"class":"form-control",
                                                         "placeholder": "备注"})#添加属性和样式
                           )
    #下拉框
    user_type_choice=(
        (0,"普通用户"),
        (1,"高级用户")
    )
    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                  attrs={'class': "form-control"}))

def user_list(request):
    obj = UserForm()
    if request.method == "POST":
        user_input_obj = UserForm(request.POST)#把提交过来的数据封装到UserForm,UserForm会自动把数据封装到user_input_obj
        if user_input_obj.is_valid():   #验证用户输入是否合法
            data = user_input_obj.clean()   #合法,获取数据
        else:
            error_msg = user_input_obj.errors.as_data()   #不合法,返回错误信息
            return render(request,"index.html",{"obj":user_input_obj,"error":error_msg})
    return render(request,"index.html",{"obj":obj,})
View Code

 

二、中间件

1、django 中的中间件(middleware),其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

  settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件

MIDDLEWARE_CLASSES = [
    #'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

 

中间件中可以定义四个方法,分别是:

  process_request(self,request)

  process_view(self, request, callback, callback_args, callback_kwargs)

  process_exception(self, request, exception)

  process_response(self, request, response)

 

每一个请求都是先通过中间件中的 process_request 函数,这个函数返回 None 或者 HttpResponse 对象,如果返回None ,继续处理其它中间件,如果返回一个 HttpResponse,就处理中止,返回到网页上

Django 会从 MIDDLEWARE_CLASSES 中按照从上到下的顺序一个个执行中间件中的 process_request 函数,而其中 process_response 函数则是最前面的最后执行。

 

2、自定义中间件

创建中间件

 

class RequestMiddleware(object):
    def process_request(self,request):
        print("process_request")
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("process_view")
    def process_exception(self, request, exception):
        print("process_exception")
    def process_response(self, request, response):
        print("process_response")
        return response

class RequestMiddleware2(object):
    def process_request(self,request):
        print("process_request2")
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("process_view2")
    def process_exception(self, request, exception):
        print("process_exception2")
    def process_response(self, request, response):
        print("process_response2")
        return response

注册中间件

settings.py

MIDDLEWARE_CLASSES = [
    #'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'app01.middleware.middle.RequestMiddleware',
    'app01.middleware.middle.RequestMiddleware2',
]

路由执行的函数

def index(request):
    print("index")
    return HttpResponse("index")

执行结果

上面是中间没有HttpResponse返回时的执行流程顺序,先执行process_request和process_view方法,在执行路由定义的函数,最后从最后一个process_response 开始执行,process_exception只会在出现异常时执行

 

三、缓存

1、由于Django是动态网站,一般来说需要实时地生成访问的网页,展示给访问者,这样,内容可以随时变化,但是从数据库读多次把所需要的数据取出来,要比从内存或者硬盘等一次读出来 付出的成本大很多。最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者Redis中,一定时间内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

 settings配置

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',#表示利用文件系统缓存
        'LOCATION': os.path.join(BASE_DIR, 'cache'),#文件路径
        'TIMEOUT': 600,
        'OPTIONS': {
            'MAX_ENTRIES': 1000
        }
    }
}

views

import time
from django.shortcuts import HttpResponse,render
from django.views.decorators.cache import cache_page

@cache_page(60 * 15)#表示缓存15分钟
def index(request):
    data=time.time()
    return HttpResponse(data)

其它的一些内建可用的 Backends

'django.core.cache.backends.db.DatabaseCache'
'django.core.cache.backends.dummy.DummyCache'
'django.core.cache.backends.filebased.FileBasedCache'
'django.core.cache.backends.locmem.LocMemCache'
'django.core.cache.backends.memcached.MemcachedCache'
'django.core.cache.backends.memcached.PyLibMCCache'
View Code

更多相关:http://djangobook.py3k.cn/2.0/chapter15/

 

四、Session和Cookie

cookie保存在客户端的电脑上,session保存与服务器

session用来在服务器端保存用户会话状态信息,依赖于cookies

操作session:

  获取  session:request.session[key]

  设置  session:reqeust.session[key] = value

  删除  session:del request[key]

request.session.set_expiry(value)

  value是个整数,session会在些秒数后失效。
  value是个datatime或timedelta,session就会在这个时间后失效。
  value是0,用户关闭浏览器session就会失效。
  value是None,session会依赖全局session失效策略。
 
 
登录认证实例:
<form class="common_form" id="Form" method="post" action="/app01/login/">
    <div><h1 class="login_title">登录</h1></div>
    <div style="width: 600px">
        <div class="form_group"><input name="username" class="form-control" label='用户名' type="text" placeholder="用户名" require='true'></div>
    </div>
    <div style="width: 600px">
        <div class="form_group"><input name="password" class="form-control" label='密码' type="password" placeholder="密码" require='true'></div>
    </div>
    <div class="form_group"><input class="btn btn-info form_btn" type="submit" value="登录"></div>
</form>
html
def login(request):
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == "zhangsan" and password == "123456":
            request.session["IS_LOGIN"] = True  #创建session
            return redirect("/app01/home/")
    return render(request,"app01/login.html")

def home(request):
    islogin = request.session.get("IS_LOGIN",False)
    if islogin:#如果用户已登录
        return render(request,"app01/menus.html")
    else:
        return redirect("/app01/login/")

def logout(request):#退出
    try:
        del request.session['IS_LOGIN']
    except KeyError:
        pass
    return redirect("/app01/login/")
views

 

更多:http://docs.30c.org/djangobook2/chapter14/

   https://docs.djangoproject.com/en/1.9/ref/settings/#settings-sessions

 

五、Ajax

1、跨站请求伪造

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成

GET 请求不需要 CSRF 认证,POST 请求需要正确认证才能得到正确的返回结果。一般在POST请求的表单中加入{% csrf_token %}

<form id="Form" method="post" action="/app01/login/">
    {% csrf_token %}
    <input name='username'  type="text">
    <input name='password'  type="password">
    <input type="submit" value="登录">
</form>

veiw中设置返回值:

return render_to_response("app01/login.html",data,context_instance=RequestContext(request))  
#或者
return render(request, "app01/login.html", data)

 

2、发送简单数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" onclick="Ajaxsubmit();" value="提交"/>

    <script type="text/javascript" src="../../static/style/js/jquery-2.2.3.js"></script>
    <script>
        function Ajaxsubmit(){
            var host = '127.0.0.1';
            var port = '8000';
            $.ajax({
                url:"/app01/user_list/",
                type:'POST',
                data:{h:host,p:port},
                success:function(arg){
                }
            })
        }
    </script>
</body>
</html>

 

2、发送复杂数据类型

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" onclick="Ajaxsubmit();" value="提交"/>

    <script type="text/javascript" src="../../static/style/js/jquery-2.2.3.js"></script>
    <script>
        function Ajaxsubmit(){
             var userlist = [
                {'username':'zhangsan','arg':18},
                {'username':'lisi','arg':20},
            ];
            $.ajax({
                url:"/app01/user_list/",
                type:'POST',
                tradition: true,
                data:{data:JSON.stringify(userlist)},//序列化
                success:function(arg){
                     var callback_dict = $.parseJSON(arg);//这里把字符串转换为对象
                    //然后咱们就可以判断
                    if(callback_dict.status){//如果为True执行失败
                        alert('提交成功')
                    }else{//如果为False执行失败
                        alert(callback_dict.error)
                    }
                }
            });
        }
    </script>
</body>
</html>

views

def user_list(request):
    ret = {'status':True,'error':''}
    try:
        print request.POST
    except Exception,e:
        ret['status'] = False   #如果出错就把ret[status] = False
        ret['error'] = str(e)
    return HttpResponse(json.dumps(ret))    #返回ret字典

 

六、静态文件引用优化

在写项目时会导入很多静态文件,而有时要修改静态文件的目录名时就比较麻烦

原来导入方式

<script type="text/javascript" src="/static/style/js/jquery-2.2.3.js"></script>

优化

  在settings的TEMPLATES里添加  'django.core.context_processors.static'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates'),],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'django.core.context_processors.static',
            ],
        },
    },
]

优化后导入

<script type="text/javascript" src="{{ STATIC_URL }}style/js/jquery-2.2.3.js"></script>

 

这样要修改目录的话只需在配置文件里修改 STATIC_URL 就可以了

 

 七、上传文件

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/app01/upload/" method="post" enctype="multipart/form-data">
        <p><input type="text" name="hostname"></p>
        <p><input type="file" name="file_name_1"></p>
        <input type="submit" value="上传">
    </form>
</body>
</html>
View Code

views

#upload
def upload(request):
    if request.method == "POST":
        file_name=request.FILES
        file_obj=file_name.get("file_name_1") #获取到封装了文件操作的对象
        f = open(file_obj.name,"wb")
        for line in file_obj.chunks(): #循环取数据
            f.write(line)   #写入
        f.close()
        return HttpResponse("ok")
    else:
        return render(request,"app01/uploadfile.html")
View Code

 

 

 

 

posted @ 2016-05-27 18:05  J_hong  阅读(689)  评论(0编辑  收藏  举报