Python之路第二十三篇--Django进阶篇

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python之路第二十三篇--Django进阶篇相关的知识,希望对你有一定的参考价值。

文件配置

1.模版Templates文件配置:

TEMPLATE_DIRS = (
        os.path.join(BASE_DIR,‘templates‘),
    )

2.静态文件static配置:

STATICFILES_DIRS = (
        os.path.join(BASE_DIR,‘static‘),
    )
Q搜索示例

1.利用Q的特性,设计多条件搜索。

技术分享
con = Q()

q1 = Q()
q1.connector = OR
q1.children.append((id, 1))
q1.children.append((id, 10))
q1.children.append((id, 9))

q2 = Q()
q2.connector = OR
q2.children.append((c1, 1))
q2.children.append((c1, 10))
q2.children.append((c1, 9))

con.add(q1, AND)
con.add(q2, AND)

ret = models.Tb1.objects.filter(con)         #QuerySet
li = list(ret)         # 转换成list 
demo

技术分享

技术分享
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .left{
            float: left;
        }
        .clearfix:after{
            content: ‘x‘;
            visibility: hidden;
            height: 0px;
            display: block;
            clear: both;
        }
    </style>
</head>
<body>
    <div class="Condition">
        <div class="item clearfix">
            <div class="icon left" onclick="AddCondition(this)"> + </div>
            <div class="left">
                <select onchange="ChangeName(this)">
                    <option value="name">书名</option>
                    <option value="book_type__caption">图书类型</option>
                    <option value="price">价格</option>
                </select>
            </div>
            <div class="left"><input type="text" name="name" placeholder="多条件 ,号分割"></div>
        </div>
    </div>
    <div><input type="button" value="提交" onclick="Search()"></div>

    <div class="ConditionTable"></div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function AddCondition(ths) {
            var new_tag = $(ths).parent().clone();
            new_tag.find(.icon).text(-).attr(onclick,RemoveCondition(this));
            $(ths).parent().parent().append(new_tag);
        };
        function RemoveCondition(ths) {
            $(ths).parent().remove();
        };
        function ChangeName(ths) {
            var v =$(ths).val();
            $(ths).parent().next().find(input).attr(name,v);
        };
        function Search() {
            var post_data_dict = {};

            $(.Condition input).each(function () {
                var n = $(this).attr(name);
                var v = $(this).val();
                var v_list = v.split(,);
                post_data_dict[n] = v_list;
            });
            var post_data_str = JSON.stringify(post_data_dict);
            $.ajax({
                url:/index/,
                type:POST,
                data:{post_data:post_data_str},
                dataType:json,
                success:function (obj) {
                    if(obj.status){
                        var table = document.createElement(table);
                        table.setAttribute(border,1);
                        $.each(obj.data,function (k,v) {
                            var tr = document.createElement(tr);
                            var td1 = document.createElement(td);
                            var td2 = document.createElement(td);
                            var td3 = document.createElement(td);
                            var td4 = document.createElement(td);
                            td1.innerText = v[name];
                            td2.innerText = v[price];
                            td3.innerText = v[pubdate];
                            td4.innerText = v[book_type__caption];
                            tr.appendChild(td1);
                            tr.appendChild(td2);
                            tr.appendChild(td3);
                            tr.appendChild(td4);
                            table.appendChild(tr);
                        });
                        $(.ConditionTable).empty();
                        $(.ConditionTable).append(table);
                    }else{

                    }
                }
            });
        };

        
    </script>
</body>
</html>
前端HTML页面
技术分享
def index(request):
    print(-----------------------------------)
    if request.method == POST:
        result = {status: False, message: ‘‘, data: None}
        try:
            post_data_str = request.POST.get(post_data,None)
            post_data_dict = json.loads(post_data_str)
            print(post_data_dict)

            Con = Q()
            for k,v in post_data_dict.items():
                q = Q()
                q.connector = OR
                for item in post_data_dict[k]:
                    q.children.append((k, item))
                Con.add(q, AND)
            # ret = models.Book.objects.filter(Con)
            # print(ret)

            # from django.core import serializers
            # data = serializers.serialize("json", ret)
            # print(type(data), data)

            ret = models.Book.objects.filter(Con).values(name,price,pubdate,book_type__caption)
            print(ret,type(ret))
            li = list(ret)
            print(li)
            result[status] = True
            result[data] = li
        except Exception as e:
            result[message] = str(e)

        result_str = json.dumps(result , cls=JsonCustomEncoder)
        return HttpResponse(result_str)
    return render(request, index.html)
后端

注意:

1.后端得到数据返回给前端ajax时,需要序列化操作,将字符串返回给前端。

2.序列化操作时,注意json默认只能转换字典,列表,元组等对象,如果为时间,小数等对象,需要自定义扩展转换成字符串。

3.表单提交中的url地址,末尾需要带上/。  如(action="/form1/")

序列化

1、serializers

from django.core import serializers

ret = models.BookType.objects.all()
 
data = serializers.serialize("json", ret)

2、json.dumps

import json
 
#ret = models.BookType.objects.all().values(‘caption‘)
ret = models.BookType.objects.all().values_list(‘caption‘)
 
ret=list(ret)
 
result = json.dumps(ret)

由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

技术分享
import json
from datetime import date
from datetime import datetime
from decimal import Decimal
class JsonCustomEncoder(json.JSONEncoder):

    def default(self, field):
        if isinstance(field, datetime):
            return field.strftime(%Y-%m-%d %H:%M:%S)
        elif isinstance(field, date):
            return field.strftime(%Y-%m-%d)
        elif isinstance(field, Decimal):
            return str(field)
        else:
            return json.JSONEncoder.default(self, field)
   
# ds = json.dumps(d, cls=JsonCustomEncoder) 
View Code
Form

Django中的Form一般有两种功能、用途:

  • 生成标签,输入html

  • 验证用户输入

1. 后端创建input标签,输入html,浏览器不同,表现不同,步骤如下:

技术分享
#!/usr/bin/env python
# -*-coding:utf-8 -*-

from django import forms

class Form1(forms.Form):
    user = forms.CharField()
    pwd = forms.CharField()
后端定义Form类型
技术分享
from app01.forms import Form1

def form1(request):
    f = Form1()
    return render(request, account/form1.html,{form:f})
后端生成Form
技术分享
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/form1/" method="POST">

        <div class="input-group">
            {{ form.user }}
        </div>

        <div class="input-group">
            {{ form.pwd }}
        </div>

        <div>
            <input type="submit"  value="提交"/>
        </div>

    </form>
</body>
</html>
前端输出Form

生成的标签,可以设置属性值:

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

title = forms.CharField(widget=forms.TextInput(attrs={class: "form-control",placeholder: u标题5-20个字符}))

memo = forms.CharField(widget=forms.widgets.Textarea(attrs={class: "form-control no-radius", placeholder: u详细描述, rows: 3}))
技术分享
from django import forms


class PublishForm(forms.Form):

    user_type_choice = (
        (0, u普通用户),
        (1, u高级用户),
    )

    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                attrs={class: "form-control"}))

    title = forms.CharField(max_length=20,
                            min_length=5,
                            widget=forms.TextInput(attrs={class: "form-control",
                                                          placeholder: u标题5-20个字符}))

    memo = forms.CharField(required=False,
                           max_length=256,
                           widget=forms.widgets.Textarea(attrs={class: "form-control no-radius", placeholder: u详细描述, rows: 3}))

    phone = forms.CharField(widget=forms.TextInput(attrs={class: "form-control",placeholder: u手机号码}))

    email = forms.EmailField(required=False,
                            widget=forms.TextInput(attrs={class: "form-control", placeholder: u邮箱}))
View Code

注意:

1.类里静态字段 只在第一遍执行!, 如果动态绑定了数据,生成后就不再修改了!

class Form1(forms.Form):
    def __init__(self,*args, **kwargs):
        super(Form1, self).__init__(*args, **kwargs)

        self.fields[book_type] =  forms.CharField(
            widget=forms.widgets.Select(choices=models.BookType.objects.values_list(id,caption),attrs={class: "form-control"}))
技术分享
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from django import forms
from app01 import models

class Form1(forms.Form):
    user = forms.CharField(
        widget=forms.TextInput(attrs={class: c1}),
        error_messages={required: 用户名不能为空},)
    pwd = forms.CharField(max_length=4,min_length=2)
    email = forms.EmailField(error_messages={required: 邮箱不能为空, invalid: 邮箱格式错误})

    memo = forms.CharField(
        widget=forms.Textarea()
    )
    # user_type_choice = (
    #     (0, ‘普通用户‘),
    #     (1, ‘高级用户‘),
    # )
    user_type_choice = models.BookType.objects.values_list(id,caption)
    book_type = forms.CharField(
        widget=forms.widgets.Select(choices=user_type_choice,attrs={class: "form-control"}))

    def __init__(self,*args, **kwargs):
        super(Form1, self).__init__(*args, **kwargs)

        self.fields[book_type] =  forms.CharField(
            widget=forms.widgets.Select(choices=models.BookType.objects.values_list(id,caption),attrs={class: "form-control"}))
完整demo

2. 验证用户输入

依据自定义的Form类,进行判断用户输入是否合法

自定义静态字段:

class Form1(forms.Form):
    user = forms.CharField( required=True
                            max_length=20,
                            min_length=5,
                            error_messages={required: u标题不能为空,
                                           min_length: u标题最少为5个字符,
                                           max_length: u标题最多为20个字符,
                                           invalid: u标题格式错误},
                            ) 

自定义正则规则:

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 Form1(forms.Form):
    phonenum= forms.CharField( validators=[mobile_validate, ],
                            )

后端验证方法: (需要传入request.POST)

from app01.forms import Form1

def form1(request):
    if request.method == POST:
        # 获取请求内容,做验证
        f = Form1(request.POST)
        if f.is_valid():
            print(f.cleaned_data)
        else:
            # print(f.errors.get(‘user‘,None))
            # print(f.errors[‘pwd‘][0])
            # print(type(f.errors),f.errors)return render(request, account/form1.html,{error: f.errors,form:f})
    else:
        f = Form1()
        return render(request, account/form1.html,{form:f})
Cookie

1、获取Cookie:

# 普通Cookie
request.COOKIES[‘key‘]
# 加密Cookie request.get_signed_cookie(key, default=RAISE_ERROR, salt=‘‘, max_age=None) 参数: default: 默认值 salt: 加密盐 (获取Cookie解密时,需要写上,否则获取得值为None ) max_age: 后台控制过期时间

2、设置Cookie:

rep = HttpResponse(...) 或 rep = render(request, ...)
 
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=‘加密盐‘,...)
    参数:
        key,              键
        value=‘‘,         值
        max_age=None,     超时时间 (单位s)  如果参数是None,这个cookie会延续到浏览器关闭为止
        expires=None,     超时时间(IE requires expires, so set it if hasn‘t been already.)  cookie失效的实际日期/时间,格式必须是:Wdy,DD-Mth-YY HH:MM:SS GMT,这个参数会覆盖max_age参数
        path=‘/‘,         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
        domain=None,      Cookie生效的域名
        secure=False,     https传输
        httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。

<script src=‘/static/js/jquery.cookie.js‘></script>
$.cookie("list_pager_num", 30,{ path: ‘/‘ });
Session

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)

  • 缓存

  • 文件

  • 缓存+数据库

  • 加密cookie

1、数据库Session

技术分享
a. 配置 settings.py
 
    SESSION_ENGINE = django.contrib.sessions.backends.db   # 引擎(默认)
     
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
配置 settings.py
技术分享
b. 使用
 
    def index(request):
        # 获取、设置、删除Session中数据
        request.session[k1]
        request.session.get(k1,None)
        request.session[k1] = 123
        request.session.setdefault(k1,123) # 存在则不设置
        del request.session[k1]
 
        # 所有 键、值、键值对
        request.session.keys()
        request.session.values()
        request.session.items()
        request.session.iterkeys()
        request.session.itervalues()
        request.session.iteritems()
 
 
        # 用户session的随机字符串
        request.session.session_key
 
        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()
 
        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")
 
        # 删除当前用户的所有Session数据
        request.session.delete("session_key")
 
        request.session.set_expiry(value)
            * 如果value是个整数,session会在些秒数后失效。
            * 如果value是个datatime或timedelta,session就会在这个时间后失效。
            * 如果value是0,用户关闭浏览器session就会失效。
            * 如果value是None,session会依赖全局session失效策略。
使用示例

2、缓存Session

技术分享
a. 配置 settings.py
 
    SESSION_ENGINE = django.contrib.sessions.backends.cache  # 引擎
    SESSION_CACHE_ALIAS = default                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
 
 
    SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次请求都保存Session,默认修改之后才保存
配置 settings.py

3、文件Session

技术分享
a. 配置 settings.py
 
    SESSION_ENGINE = django.contrib.sessions.backends.file    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
 
 
    SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                               # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次请求都保存Session,默认修改之后才保存
配置 settings.py

4、缓存+数据库Session

技术分享
数据库用于做持久化,缓存用于提高效率
 
a. 配置 settings.py
 
    SESSION_ENGINE = django.contrib.sessions.backends.cached_db        # 引擎
配置 settings.py

5、加密cookie Session

技术分享
a. 配置 settings.py
     
    SESSION_ENGINE = django.contrib.sessions.backends.signed_cookies   # 引擎
配置 settings.py

更多参考:猛击这里 和 猛击这里

扩展:Session用户验证

def login(func):
    def wrap(request, *args, **kwargs):
        # 如果未登陆,跳转到指定页面
        if request.path == ‘/test/‘:
            return redirect(‘http://www.baidu.com‘)
        return func(request, *args, **kwargs)
    return wrap
分页

一、Django内置分页

二、自定义分页

csrf跨站请求伪造

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

  中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

  • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。

  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

注: 需要引入

from django.views.decorators.csrf import csrf_exempt,csrf_protect

二、应用

1、普通表单

veiw中设置返回值:
  return render_to_response(‘Account/Login.html‘,data,context_instance=RequestContext(request))  
     或者
   return render(request, ‘xxx.html‘, data)
  
html 表单中设置Token:
  {% csrf_token %}

2、Ajax

1.对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,添加请求头

2.为了方便,获取cookie,需要用到 jquery.cookie.js 文件提供的$.cookie()方法

var csrftoken = $.cookie(csrftoken);

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

admin

django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:

  • 创建后台管理员

  • 配置url

  • 注册和配置django admin后台管理页面

1、创建后台管理员

python manage.py createsuperuser

2、配置后台管理url

url(r‘^admin/‘, include(admin.site.urls))

3、注册和配置django admin 后台管理页面

a、在admin中执行如下配置

技术分享
from django.contrib import admin
  
from app01 import  models
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)

admin.site.register(models.xxxxx)  # 自己创建的表
View Code

b、设置数据表名称

技术分享
class UserType(models.Model):
    name = models.CharField(max_length=50)
  
    class Meta:
        verbose_name = 用户类型
        verbose_name_plural = 用户类型
View Code

c、打开表之后,设定默认显示,需要在model中作如下配置

技术分享
class UserType(models.Model):
    name = models.CharField(max_length=50)
    
   #py2
    def __unicode__(self):
        return self.name

    #py3
    def __str__(self):
        return self.name
View Code
技术分享
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = (username, password, email)
View Code

d、为数据表添加搜索功能

技术分享
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = (username, password, email)
    search_fields = (username, email)
View Code

e、添加快速过滤

技术分享
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = (username, password, email)
    search_fields = (username, email)
    list_filter = (username, email)
View Code

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

 

以上是关于Python之路第二十三篇--Django进阶篇的主要内容,如果未能解决你的问题,请参考以下文章

Python之路第二十三篇:数据库基础

C++进阶第二十三篇——位图(概念+实现)

Django 第二十三篇优化查询

C++进阶第二十三篇——位图(概念+实现)

Python之路第二十二章:Django 进阶

python全栈开发基础第二十三篇线程