Django框架基础知识汇总(无项目版)

一、WEB框架本质


所有的Web应用,本质上其实是一个socket服务端,用户浏览器是一个socket客户端.

#!/usr/bin/env python
#coding:utf-8
# 服务端SOCKET 
import socket  
def handle_request(client):
    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n")
    client.send("Hello, Seven")  
def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost',8000))
    sock.listen(5)  
    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()
  if __name__ == '__main__':
    main()

python web程序分为两部分:服务器程序和应用程序。
服务器程序负责对socket服务器进行封装,在请求到来时对请求的各种数据进行整理。应用程序则负责具体的逻辑处理。

WSGI(Web Server Gateway Interface)是一种规范。它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。

from wsgiref.simple_server import make_server

def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ] 

if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print("Serving HTTP on port 8000...")
    httpd.serve_forever()

二、自定义Web框架


  • 框架:

python标准库提供的独立WSGI服务器称为wsgiref。

#通过python标准库提供的wsgiref模块开发一个自己的Web框架

#!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server 
def index():
    return 'index' 
def login():
    return 'login' 
def routers():     
    urlpatterns = (
        ('/index/',index),
        ('/login/',login),
    )     
    return urlpatterns 
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    urlpatterns = routers()
    func = None
    for item in urlpatterns:
        if item[0] == url:
            func = item[1]
            break
    if func:
        return func()
    else:
        return '404 not found'     
if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()

模板引擎生成静态内容:

在上叙中,所有login、index均返回给用户浏览器简单字符串,在现实的Web请求中会返回一个复杂的符合HTML规则的字符串,需将要返回给用户的HTML写在指定文件中,然后再返回,如:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>Index</h1>
</body>
</html>


<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form>
        <input type="text" />
        <input type="text" />
        <input type="submit" />
    </form>
</body>
</html>
……views模块内容:
def index():
    # return 'index'
    f = open('index.html')
    data = f.read()
    return data 
def login():
    # return 'login'
    f = open('login.html')
    data = f.read()
    return data 
……

开源工具Jinja2实现动态内容:

上述代码返回给用户HTML的内容来现实复杂的页面,但如何给用户返回动态内容?

  • 自定义一套特殊的语法,进行替换
  • 使用开源工具jinja2,遵循其指定语法
# index.html文件内容:
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>{{name}}</h1>
    <ul>
        {% for item in user_list %}
        <li>{{item}}</li>
        {% endfor %}
    </ul>
</body>
</html>

#遵循jinja2的语法规则,其内部会对指定的语法进行相应的替换,从而达到动态的返回内容:

#!/usr/bin/env python
# -*- coding:utf-8 -*- 
from wsgiref.simple_server import make_server
from jinja2 import Template 

def index():
    # return 'index' 
    # template = Template('Hello {{ name }}!')
    # result = template.render(name='John Doe') 
    f = open('index.html')
    result = f.read()
    template = Template(result)
    data = template.render(name='John Doe', user_list=['alex', 'eric'])
    return data.encode('utf-8') 
def login():
    # return 'login'
    f = open('login.html')
    data = f.read()
    return data 
def routers(): 
    urlpatterns = (
        ('/index/', index),
        ('/login/', login),
    ) 
    return urlpatterns 
def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    urlpatterns = routers()
    func = None
    for item in urlpatterns:
        if item[0] == url:
            func = item[1]
            break
    if func:
        return func()
    else:
        return '404 not found' 
if __name__ == '__main__':
    httpd = make_server('', 8000, run_server)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()

三、Django基本配置


创建django程序:

  • 终端命令:django-admin startproject sitename
  • IDE创建Django程序时,本质上都是自动执行上述命令
    其他常用命令:
    python manage.py runserver 0.0.0.0
    python manage.py startapp appname # 创建app程序模块
    python manage.py syncdb
    python manage.py makemigrations
    python manage.py migrate
    python manage.py createsuperuser

程序目录:

mysite
mysit
init.py
settings.py
urls.py
wsgi.py
templates
manage.py

setting.py 配置文件:

Mysql数据库:
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’:’dbname’,
‘USER’: ‘root’,
‘PASSWORD’: ‘xxx’,
‘HOST’: ”,
‘PORT’: ”,
}
}

备注:
由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
如下设置放置的与project同名的配置的 init.py文件中
**import pymysql
pymysql.install_as_MySQLdb()** 

四、路由系统


单一路由对应:
url(r’^index$’, views.index)

.

基于正则的路由:
url(r’^index/(\d*)’, views.index), # 匹配0到无穷个数字
url(r’^manage/(?P\w*)/(?P\d*)’, views.manage), # 匹配到两个组,别名分别为name,id

.

添加额外的参数:
url(r’^manage/(?P\w*)’, views.manage,{‘id’:333}), #> 视图函数中的参数可接收id

.

为路由映射设置名称:

url(r’^home’, views.home, name=’h1’),
url(r’^index/(\d*)’, views.index, name=’h2’),

设置名称之后,可以在不同的地方调用,如:
模板中使用生成URL {% url ‘h2’ 2012 %}

函数中使用生成URL reverse(‘h2’, args=(2012,)) 路径:django.urls.reverse
Model中使用获取URL 自定义get_absolute_url() 方法:

class NewType(models.Model):
    caption = models.CharField(max_length=16)
    def get_absolute_url(self):
        """
        为每个对象生成一个URL
        应用:在对象列表中生成查看详细的URL,使用此方法即可!!!
        :return:
        """
        # return '/%s/%s' % (self._meta.db_table, self.id)
        # 或
        from django.urls import reverse
        return reverse('NewType.Detail', kwargs={'nid': self.id})

根据app对路由规则进行分类:
url(r’^web/’,include(‘web.urls’)),

命名空间:
# a. project.urls.py:
from django.conf.urls import url,include 
urlpatterns = [
    url(r'^a/', include('app01.urls', namespace='author-polls')),
    url(r'^b/', include('app01.urls', namespace='publisher-polls')),
]

# b. app01.urls.py:
from django.conf.urls import url
from app01 import views 
app_name = 'app01'
urlpatterns = [
    url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]

# c. app01.views.py:
def detail(request, pk):
    print(request.resolver_match)
    return HttpResponse(pk)

# 以上定义带命名空间的url之后,使用name反向生成URL时候,应该如下:
v = reverse('app01:detail', kwargs={'pk':11})
{% url 'app01:detail' pk=12 pp=99 %}

django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给一个views中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而是路由系统变得简洁。

五、模板


模版的执行:

模版的创建过程,是读取模版(其中嵌套着模版标签),然后将 Model 中获取的数据插入到模版中,最后将信息返回给用户.

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

内置模版语言:

{{ item }}   # 获得字典数据
{% for item in item_list %}  <a>{{ item }}</a>  {% endfor %}  # for循环出数据
  forloop.counter
  forloop.first
  forloop.last 
{% if ordered_warranty %}  {% else %} {% endif %}   # if判断数据
母板:{% block title %}{% endblock %}   # title为母板名称
子板:{% extends "base.html" %}
   {% block title %}{% endblock %}  # 子板继承母板title
帮助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}}    # 日期函数应用
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}   # simple_tag实现模板中加载函数执行
{{ name|lower }}    # 模版中应用小写的函数

自定义simple_tag模版语言:

定义:

a、在app中创建templatetags模块文件夹
b、创建任意 .py 文件,如:xx.py
# xx.py 文件内容如下:

#!/usr/bin/env python
#coding:utf-8
from django import template
from django.utils.safestring import mark_safe   
register = template.Library()   
@register.simple_tag
def my_simple_time(v1,v2,v3):
    return  v1 + v2 + v3   
@register.simple_tag   # 将函数注册到simple_tag中
def my_input(id,arg):   # 定义处理的函数
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)   # 创建html能识别的格式标签,而非字符

使用方式:

使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}  # 加载自定义的simple_tag 所在的文件名
{% my_simple_time 1 2 3%} # 使用自定义的simple_tag函数名,并传入参数
{% my_input 'id_username' 'hide'%}

注意:

在settings中配置当前app,不然django无法找到自定义的simple_tag:
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
     'app01',   # 注册
)

七、中间件


中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件。
中间件中可以定义5个方法,分别是:

process_request(self,request)   # 重要
process_view(self, request, callback, callback_args, callback_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)   # 重要

以上方法的返回值可以是None和HttpResonse对象。
如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户,不再走其他中间件的request方法

引用块内容:

创建中间件类:

class RequestExeute(object):      
    def process_request(self,request):    # 先执行所有中间件的process_request函数
        pass
    def process_view(self, request, callback, callback_args, callback_kwargs):
        i =1
        pass
    def process_exception(self, request, exception):
        pass      
    def process_response(self, request, response):  #所有中间件的所有process_request执行完后再执行process_response函数
        return response

注册中间件:

 MIDDLEWARE_CLASSES = (
    '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',
    'wupeiqi.middleware.auth.RequestExeute',
)

八、admin后台


使用步骤:

django amdin是django提供的一个后台管理页面,该管理页面提供完善的html和css,
使得在通过Model创建完数据库表后,就可对数据直接进行增删改查。

  • 创建后台管理员:python manage.py createsuperuser
  • 配置url :url(r’^admin/’, include(admin.site.urls)) # 默认会自动生成
  • 注册和配置django admin后台管理页面:
    .
# 设置数据表名称:
class UserType(models.Model):
    name = models.CharField(max_length=50)  
    class Meta:   # 元信息类
        verbose_name = '用户类型'
        verbose_name_plural = '用户类型'
# 在admin.py模块中执行如下配置:
from django.contrib import admin  
from app01 import  models  
admin.site.register(models.UserType)   # 将model模块中的UserType类注册到admin中
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
# 打开表之后,可设定默认显示,需要在model.py模块中作如下配置:
class UserType(models.Model):
    name = models.CharField(max_length=50)  
    def __unicode__(self):
        return self.name

class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')  # 默认显示
# 为数据表添加搜索功能:
from django.contrib import admin  
from app01 import  models

class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')
    search_fields = ('username', 'email')   # 搜索功能
# 添加快速过滤:
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')   # 快速过滤

八、Model类


使用前准备工作:

  • 创建数据库,设计表结构和字段
  • 使用 MySQLdb 来连接数据库,并编写数据访问层代码
  • 业务逻辑层去调用数据访问层执行数据库操作
import MySQLdb 
def GetList(sql):
    db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')   # 连接数据库
    cursor = db.cursor()   # 获得游标
    cursor.execute(sql)   # 执行sql语句
    data = cursor.fetchall()   # 获得数据表所有数据
    db.close()   # 关闭连接
    return data  

def GetSingle(sql):
    db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
    cursor = db.cursor()
    cursor.execute(sql)
    data = cursor.fetchone()
    db.close()
    return data

django为使用一种新的方式,即:对象关系映射(Object Relational Mapping,简称ORM)。
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。

创建数据表:

- 基本结构:

from django.db import models   
class userinfo(models.Model):
    name = models.CharField(max_length=30)   # 定义字符格式字段
    email = models.EmailField()   # 邮箱格式字段,会自动进行格式校验
    memo = models.TextField()   # 文本格式字段

- 字段:


AutoField(Field)   # int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField)   # bigint自增列,必须填入参数 primary_key=True

# 注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import models
class UserInfo(models.Model):    
    username = models.CharField(max_length=32) # 自动创建一个列名为id的且为自增的整数列在其中
class Group(models.Model):   
    nid = models.AutoField(primary_key=True)    # 手动自定义自增列
    name = models.CharField(max_length=32)

SmallIntegerField(IntegerField):   # 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)    # 正小整数 0 ~ 32767
IntegerField(Field)   # 整数列(有符号的) -2147483648 ~ 2147483647
BigIntegerField(IntegerField):   # 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

# 自定义无符号整数字段:
class UnsignedIntegerField(models.IntegerField):
    def db_type(self, connection):
        return 'integer UNSIGNED'
# PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',

BooleanField(Field)   # 布尔值类型
NullBooleanField(Field):   # 可以为空的布尔值
CharField(Field)   # 字符类型,必须提供max_length参数, max_length表示字符长度
TextField(Field)   # 文本类型
EmailField(CharField): # 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field)   # 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

GenericIPAddressField(Field)   # 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
  # 参数:
       protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
       unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要 protocol="both"

URLField(CharField)   # 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)   # 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)   # 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)   # 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field)   # 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
  # 参数:
       path,                      文件夹路径
       match=None,                正则匹配
       recursive=False,           递归下面的文件夹
       allow_files=True,          允许文件
       allow_folders=False,       允许文件夹
FileField(Field)   # 字符串,路径保存在数据库,文件上传到指定目录
   # 参数:
       upload_to = ""      上传文件的保存路径
       storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)   # 字符串,路径保存在数据库,文件上传到指定目录
    # 参数:
        upload_to = ""      上传文件的保存路径
        storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
        width_field=None,   上传图片的高度保存的数据库字段名(字符串)
        height_field=None   上传图片的宽度保存的数据库字段名(字符串)

DateTimeField(DateField)   # 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)   # 日期格式      YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)   # 时间格式      HH:MM[:ss[.uuuuuu]]
DurationField(Field)   # 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

FloatField(Field)   # 浮点型
DecimalField(Field)   # 10进制小数
   # 参数:
       max_digits,小数总长度
       decimal_places,小数位长度
BinaryField(Field)   # 二进制类型

- 参数:

null                数据库中字段是否可以为空
db_column           数据库中字段的列名
db_tablespace
default             数据库中字段的默认值
primary_key         数据库中字段是否为主键
db_index            数据库中字段是否可以建立索引
unique              数据库中字段是否可以建立唯一索引
unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
unique_for_year     数据库中字段【年】部分是否可以建立唯一索引

verbose_name        Admin中显示的字段名称
blank               Admin中是否允许用户输入为空
editable            Admin中是否可以编辑
help_text           Admin中该字段的提示信息
choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                   如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                   字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                   如:{'null': "不能为空.", 'invalid': '格式错误'}

validators          自定义错误验证(列表类型),从而定制想要的验证规则
                   from django.core.validators import RegexValidator
                   from django.core.validators import EmailValidator,URLValidator,DecimalValidator,                   
                   MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                   如:
                       test = models.CharField(
                           max_length=32,
                           error_messages={
                               'c1': '优先错信息1',
                               'c2': '优先错信息2',
                               'c3': '优先错信息3',
                           },
                           validators=[
                               RegexValidator(regex='root_\d+', message='错误了', code='c1'),
                               RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
                               EmailValidator(message='又错误了', code='c3'), ]
                       )

- 元信息:

class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)
        class Meta:
            # 数据库中生成的表名称: app名称 + 下划线 + 类名  (默认生成)
            db_table = "table_name"
            # 联合索引
            index_together = [
                ("pub_date", "deadline"),
            ]
            # 联合唯一索引
            unique_together = (("driver", "restaurant"),)
            # admin中显示的表名称
            verbose_name
            # verbose_name加s
            verbose_name_plural

- 补充知识:

1.触发Model中的验证和错误提示有两种方式:
a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息。
b. 调用Model对象的 clean_fields 方法,如:
            # models.py
            class UserInfo(models.Model):
                nid = models.AutoField(primary_key=True)
                username = models.CharField(max_length=32)
                email = models.EmailField(error_messages={'invalid': '格式错了.'})

            # views.py
            def index(request):
                obj = models.UserInfo(username='11234', email='uu')
                try:
                    print(obj.clean_fields())
                except Exception as e:
                    print(e)
                return HttpResponse('ok')

           # Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。

    2.Admin中修改错误提示:
        # admin.py
        from django.contrib import admin
        from model_club import models
        from django import forms

        class UserInfoForm(forms.ModelForm):
            username = forms.CharField(error_messages={'required': '用户名不能为空.'})
            email = forms.EmailField(error_messages={'invalid': '邮箱格式错误.'})
            age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'})

        class Meta:
            model = models.UserInfo
            # fields = ('username',)
            fields = "__all__" 

        class UserInfoAdmin(admin.ModelAdmin):
            form = UserInfoForm
       admin.site.register(models.UserInfo, UserInfoAdmin)   # 注册到admin组件中

创建连表:

  • 一对多:models.ForeignKey(其他表)
  • 多对多:models.ManyToManyField(其他表)
  • 一对一:models.OneToOneField(其他表)

应用场景:

  • 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
    例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
  • 多对多:在某表中创建一行数据是,有一个可以多选的下拉框
    例如:创建用户信息,需要为用户指定多个不同的爱好,生成多条1个用户与不同爱好关联的数据,且一个爱好对应多个用户的数据。
  • 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了,相当于一对多+唯一性约束)
    例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列新的数据

字段以及参数:

  • ForeignKey
ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                         # 要进行关联的表名
        to_field=None,              # 要关联的表中的字段名称
        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为
                                        - models.CASCADE,删除关联数据,与之关联也删除
                                        - models.DO_NOTHING,删除关联数据,引发错误IntegrityError
                                        - models.PROTECT,删除关联数据,引发错误ProtectedError
                                        - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
                                        - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
                                        - models.SET,删除关联数据,
                                                      a. 与之关联的值设置为指定值,设置:models.SET(值)
                                                      b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

 def func():
     return 10
 class MyModel(models.Model):
     user = models.ForeignKey(
         to="User",
         to_field="id"
         on_delete=models.SET(func),)

        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:

# 如:
     - limit_choices_to={'nid__gt': 5}
     - limit_choices_to=lambda : {'nid__gt': 5}

     from django.db.models import Q
     - limit_choices_to=Q(nid__gt=10)
     - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
     - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

        db_constraint=True          # 是否在数据库中创建外键约束
        parent_link=False           # 在Admin中是否显示关联数据
  • OneToOneField:
OneToOneField(ForeignKey)
to,                         # 要进行关联的表名
to_field=None               # 要关联的表中的字段名称
on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为

###### 对于一对一 ######
 # 1. 一对一其实就是 一对多 + 唯一索引
 # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
 # 如下会在A表中额外增加一个c_part_id列且唯一:
class C(models.Model):
    nid = models.AutoField(primary_key=True)
    part = models.CharField(max_length=12)

class A(C):
    id = models.AutoField(primary_key=True)
    code = models.CharField(max_length=1)
  • ManyToManyField:
ManyToManyField(RelatedField)
to,                         # 要进行关联的表名
related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件: 
# 如:
 - limit_choices_to={'nid__gt': 5}
 - limit_choices_to=lambda : {'nid__gt': 5}

 from django.db.models import Q
 - limit_choices_to=Q(nid__gt=10)
 - limit_choices_to=Q(nid=8) | Q(nid__gt=10)

symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
# 做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
# 可选字段有:code, id, m1
class BB(models.Model):
    code = models.CharField(max_length=12)
    m1 = models.ManyToManyField('self',symmetrical=True)

# 可选字段有: bb, code, id, m1
class BB(models.Model):
    code = models.CharField(max_length=12)
    m1 = models.ManyToManyField('self',symmetrical=False)

through=None,               # 自定义第三张表时,使用字段用于指定关系表
through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表

from django.db import models
 class Person(models.Model):
     name = models.CharField(max_length=50)

 class Group(models.Model):
     name = models.CharField(max_length=128)
     members = models.ManyToManyField(
         Person,
         through='Membership',
         through_fields=('group', 'person'),
     )

class Membership(models.Model):
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    inviter = models.ForeignKey(
        Person,
        on_delete=models.CASCADE,
        related_name="membership_invites",
    )
     invite_reason = models.CharField(max_length=64)
     db_constraint=True,         # 是否在数据库中创建外键约束
     db_table=None,              # 默认创建第三张表时,数据库中表的名称

单表操作:

  • 基本操作:
     增    
     models.Tb1.objects.create(c1='xx', c2='oo')  增加一条数据,可以接受字典类型数据 **kwargs

     obj = models.Tb1(c1='xx', c2='oo')
     obj.save()

     查
     models.Tb1.objects.get(id=123)            # 获取单条数据,不存在则报错(不建议)
     models.Tb1.objects.filter().first   # 推荐该方式获取单条数据
     models.Tb1.objects.all()                  #获取全部
     models.Tb1.objects.filter(name='seven')   #获取指定条件的数据

     删
     models.Tb1.objects.filter(name='seven').delete()  删除指定条件的数据

     改
     models.Tb1.objects.filter(name='seven').update(gender='0')   将指定条件的数据更新,均支持 **kwargs
第2种修改数据方式:
     obj = models.Tb1.objects.get(id=1)
     obj.c1 = '111'   # 对c1字段进行赋值班
     obj.save()                                                  修改单条数据
  • 进阶操作 (双下划线连表操作)
# 获取个数:       
         models.Tb1.objects.filter(name='seven').count()

        # 大于,小于:        
         models.Tb1.objects.filter(id__gt=1)               获取id大于1的值
         models.Tb1.objects.filter(id__gte=1)               获取id大于等于1的值
         models.Tb1.objects.filter(id__lt=10)              获取id小于10的值
         models.Tb1.objects.filter(id__lte=10)              获取id小于10的值
         models.Tb1.objects.filter(id__lt=10, id__gt=1)    获取id大于1 且 小于10的值,等价于and

         #in,范围有效值判断         
         models.Tb1.objects.filter(id__in=[11, 22, 33])    获取id等于112233的数据
         models.Tb1.objects.exclude(id__in=[11, 22, 33])   等价于 not in

         # isnull,判断是否为空
         Entry.objects.filter(pub_date__isnull=True)

         # contains 表中字段是否包含某一个值       
         models.Tb1.objects.filter(name__contains="ven")
         models.Tb1.objects.filter(name__icontains="ven")   # icontains大小写不敏感
         models.Tb1.objects.exclude(name__icontains="ven")

         # range 范围判断       
         models.Tb1.objects.filter(id__range=[1, 2])    范围bettwen and
         # 其他类似:        
         startswith,istartswith, endswith, iendswith,

         # order by排序        
         models.Tb1.objects.filter(name='seven').order_by('id')     # asc升序
         models.Tb1.objects.filter(name='seven').order_by('-id')    # desc降序

         # group by分组        
         from django.db.models import Count, Min, Max, Sum
         models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) #以id为分组条件,分组结果字段别名为c,获取每个组中num字段的数量
         #等价于:SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

         # limit限制查询数据, offset偏移 :       
         models.Tb1.objects.all()[10:20]

         # regex正则匹配,iregex 不区分大小写:        
         Entry.objects.get(title__regex=r'^(An?|The) +')  # 至少有一个以An或The开头的内容
         Entry.objects.get(title__iregex=r'^(an?|the) +')

         # date日期        
         Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))  # 查询pub_date字段中日期为2005,1,1的数据
         Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

         # year:        
         Entry.objects.filter(pub_date__year=2005)
         Entry.objects.filter(pub_date__year__gte=2005)

         # month:        
         Entry.objects.filter(pub_date__month=12)
         Entry.objects.filter(pub_date__month__gte=6)

         # day:        
         Entry.objects.filter(pub_date__day=3)
         Entry.objects.filter(pub_date__day__gte=3)

         # week_day:        
         Entry.objects.filter(pub_date__week_day=2)
         Entry.objects.filter(pub_date__week_day__gte=2)

         # hour:        
         Event.objects.filter(timestamp__hour=23)
         Event.objects.filter(time__hour=5)
         Event.objects.filter(timestamp__hour__gte=12)

         # minute:        
         Event.objects.filter(timestamp__minute=29)
         Event.objects.filter(time__minute=46)
         Event.objects.filter(timestamp__minute__gte=29)

         # second(秒):        
         Event.objects.filter(timestamp__second=31)
         Event.objects.filter(time__second=2)
         Event.objects.filter(timestamp__second__gte=31)
  • 其它高级操作:
 # extra (添加额外语句)   
     extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
例:
        Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
        Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
        Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
        Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

#F  (找到数据表字段)  
     from django.db.models import F
     models.Tb1.objects.update(num=F('num')+1) # 在所有的num字段基础上加1


# Q (条件组合)    
     方式一:
     Q(nid__gt=10)
     Q(nid=8) | Q(nid__gt=10)
     Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

     方式二:
     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')    
     models.Tb1.objects.filter(con)

# 等价于((id=1)or(id=10)or(id=9))and((c1=1)or(c1=10)or(c1=9))


# 通过sqlAlchemy执行原生SQLfrom django.db import connection, connections
     cursor = connection.cursor()   # 创建游标
cursor = connections['default'].cursor()    # 设置游标
     cursor.execute("SELECT * from auth_user where id = %s", [1])   # 执行sql语句
     row = cursor.fetchone()    # 获取一条数据

连表操作:

  • 表结构
class UserProfile(models.Model):
    user_info = models.OneToOneField('UserInfo')
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

    def __str__(self): 
        return self.username


class UserInfo(models.Model):
    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )
    user_type = models.IntegerField(choices=user_type_choice)
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    address = models.CharField(max_length=128)

    def __str__(self):
        return self.name


class UserGroup(models.Model):

    caption = models.CharField(max_length=64)

    user_info = models.ManyToManyField('UserInfo')

    def __str__(self):
        return self.caption


class Host(models.Model):
    hostname = models.CharField(max_length=64)
    ip = models.GenericIPAddressField()
    user_group = models.ForeignKey('UserGroup')

    def __str__(self):
        return self.hostname

九、扩展内容:(上传文件)


  • 自定义上传文件:
def upload_file(request):
    if request.method == "POST":
        obj = request.FILES.get('fafafa')   # 获得文件对象
        f = open(obj.name, 'wb')    # 创建文件句柄,以字节形式写入文件
        for chunk in obj.chunks():  # 获得文件块
            f.write(chunk)  # 将文件块写入文件
        f.close()
    return render(request, 'file.html')
  • Form上传文件实例:
Form定义:

class FileForm(forms.Form):
    ExcelFile = forms.FileField() # 定义表单中的文件上传组件
Model类定义:
from django.db import models

class UploadFile(models.Model):
    userid = models.CharField(max_length = 30)
    file = models.FileField(upload_to = './upload/')
    date = models.DateTimeField(auto_now_add=True) # 自动添加日期
views:
def UploadFile(request):
    uf =  FileForm(request.POST,request.FILES)   # 将请求中的数据发送给定义的Form组件进行校验
    if uf.is_valid():   # 校验通过,Form组件中包含用户输入到字段对应的值
            upload = models.UploadFile()   # 实例化Model类,获得对象
            upload.userid = 1   # 为对象的userid赋值,可以对应成是为数据表中的字段赋值
            upload.file = uf.cleaned_data['ExcelFile']  # 从Form组件中获得ExcelFile中的值传给Model类中对应数据表中的字段
            upload.save()   # 将该条数据保存到数据库

            print (upload.file)

十、Form内置组件


django中的Form一般有2种功能:

  • 输入html(生成表单组件)
  • 验证用户输入

Form:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
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 PublishForm(forms.Form):  # 定义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,
                            error_messages={'required': u'标题不能为空',
                                            'min_length': u'标题最少为5个字符',
                                            'max_length': u'标题最多为20个字符'},
                            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(validators=[mobile_validate, ], # 添加验证器,对用户在该表单组件中输入的值进行正则表达式函数的验证
                            error_messages={'required': u'手机不能为空'},   # 设置验证不通过时前端显示的错误信息
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))

    email = forms.EmailField(required=False,    # 该字段非必填项
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

views:

def publish(request):
    ret = {'status': False, 'data': '', 'error': '', 'summary': ''}   # 定义返回参数
    if request.method == 'POST':
        request_form = PublishForm(request.POST)  # 将请求数据传入Form组件进行验证
        if request_form.is_valid():
            request_dict = request_form.clean()  # 获得Form组件验证过的数据            
            ret['status'] = True
        else:
            error_msg = request_form.errors.as_json()  # 获得错误信息列表的json字符串
            ret['error'] = json.loads(error_msg) # 将json字符串转换为字典对象
    return HttpResponse(json.dumps(ret))  # 将字典对象转换成json字符串进行传输

扩展ModelForm:

在使用Model和Form时,都需要对字段进行定义并指定类型,
通过ModelForm则可以省去From中字段的定义。
class AdminModelForm(forms.ModelForm):

    class Meta:
        model = models.Admin
        #fields = '__all__'
        fields = ('username', 'email')

        widgets = {
            'email' : forms.PasswordInput(attrs={'class':"alex"}),
        }

十一、跨站请求伪造攻击(crsf)


简介:

crsf会生成随机字符串发送给前端,前端请求可携带随机字符串来进行识别。
django为用户实现防止跨站请求伪造的功能,
通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。
而对于django中设置防跨站请求伪造功能有分为全局和局部。

 - 全局:
在settion配置文件中添加中间件 django.middleware.csrf.CsrfViewMiddleware
 - 局部:
@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

应用:

  • 普通Form表单:
veiw中设置返回值:
  return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))  
     或者
     return render(request, 'xxx.html', data)  # 返回的request请求中包含crsf随机字符串发送给前端

html中设置Token:
  {% csrf_token %}  # 从返回中的request中取出crsf_token随机字符串,再次发送请求时,将该值传递给中间件验证
  • Ajax实现跨站请求验证:
# html部分:
<form method="POST" action="/csrf1.html">
    {% csrf_token %}
    <input id="user" type="text" name="user" />
    <input type="submit" value="提交"/>
    <a onclick="submitForm();">Ajax提交</a>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>
# js文件部分:
<script>
    function submitForm(){
        var token = $.cookie('csrftoken'); # 获得cookies中的csrf随机字符串
        var user = $('#user').val();
        $.ajax({
            url: '/csrf1.html',
            type: 'POST',
            headers:{'X-CSRFToken': token}, # 将数据添加到请求头中,让Django去取,硬性规定
            data: { "user":user},
            success:function(arg){
                console.log(arg);
            }
        })
    }
</script>
# views部分

def csrf1(request):
    if request.method == 'GET':
        return render(request,'csrf1.html')  # request中有cookies,其中包含crsf随机字符串发送给前端
    else:
        return HttpResponse('ok')

十二、Cookie


后台获取请求中Cookie:

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)   # 获得加盐后的cookies
参数:
     default: 默认值
        salt: 加密盐
     max_age: 后台控制过期时间

后台设置Cookie:

rep = HttpResponse(...) 或 rep = render(request, ...) 
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
    参数:
        key,             键
        value='',         值
        max_age=None,     超时时间
        expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
        path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
        domain=None,      Cookie生效的域名
        secure=False,     https传输
        httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

前端获取Cookies:

由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
<script src='/static/js/jquery.cookie.js'></script>
$.cookie("list_pager_num", 30,{ path: '/' });

十三、Session


简介:

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

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie

数据库Session:

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。

配置 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,默认修改之后才保存(默认) 
  • 使用示例:
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的随机字符串 在数据库中是否存在(传入cookies中的key,它对应的value是随机字符串)
        request.session.exists("session_key")

        # 删除当前用户的所有Session数据
        request.session.delete("session_key")

                        # 设置session生命周期
        request.session.set_expiry(value)
            * 如果value是个整数,session会在些秒数后失效。
            * 如果value是个datatime或timedelta,session就会在这个时间后失效。
            * 如果value是0,用户关闭浏览器session就会失效。
            * 如果value是None,session会依赖全局session失效策略。

缓存session:

 # 配置 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,默认修改之后才保存 

文件Session:

# 配置 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,默认修改之后才保存

缓存+数据库Session:

数据库用于做持久化,缓存用于提高效率: 
a. 配置 settings.py 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'      
      # 引擎
……
 b. 使用 
    同上

加密cookies:

a. 配置 settings.py     
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎 
    ……
b. 使用 
    同上

扩展: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内置分页:

# views:

from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

L = []
for i in range(999):
    L.append(i)

def index(request):
    current_page = request.GET.get('p')

    paginator = Paginator(L, 10)   # 传入数据及每页需要显示的条数
    # per_page: 每页显示条目数量
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    try:
        posts = paginator.page(current_page)
        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表
        # number                当前页
        # paginator             paginator对象
    except PageNotAnInteger:
        posts = paginator.page(1)  # 返回第1页
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)  # 返回最后一页
    return render(request, 'index.html', {'posts': posts})  # 
# html:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul>
    {% for item in posts %}
        <li>{{ item }}</li>  # 当前页对应的所有数据
    {% endfor %}
</ul>

<div class="pagination">
      <span class="step-links">
        {% if posts.has_previous %}   # 是否有上一页
            <a href="?p={{ posts.previous_page_number }}">Previous</a>   #  posts.previous_page_number表示 上一页页码
        {% endif %}

          <span class="current">
            Page {{ posts.number }} of {{ posts.paginator.num_pages }}   # 当前页
          </span>

          {% if posts.has_next %}   # 是否有下一页
              <a href="?p={{ posts.next_page_number }}">Next</a> # posts.previous_page_number表示 下一页页码
          {% endif %}
      </span>
</div>
</body>
</html>

自定义分页:

分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入,计算出应该在数据库表中的起始位置。

数据显示部分:
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
4、在数据表中根据起始位置取值,页面上输出数据
页数显示部分:(如:[上一页][1][2][3][4][5][下一页])
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...3、设定显示多少页号
4、获取当前数据总条数
5、根据设定显示多少页号和数据总条数计算出总页数
6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
7、在数据表中根据起始位置取值,页面上输出数据
8、输出分页html,如:[上一页][1][2][3][4][5][下一页]
#!/usr/bin/env python
# _*_coding:utf-8_*_
from django.utils.safestring import mark_safe

class PageInfo(object):
    def __init__(self,current,totalItem,peritems=5):    # current:当前页; totalItem:数据库查出的数据总条数; peritems:每页显示的条数,默认值为5条
        self.__current=current
        self.__peritems=peritems
        self.__totalItem=totalItem
""" 根据当前页码数计算出数据表的查询范围 """
# 范围查询范例:models.UserInfo.objects.all()[page_info.start():page_info.end()]
    def From(self): # 根据当前页获得从数据库中进行范围查询时的起始序号
        return (self.__current-1)*self.__peritems
    def To(self):
        return self.__current*self.__peritems   #  根据当前页获得从数据库中进行范围查询时的结束序号
    def TotalPage(self):  # 计算显示页码部分的总页数
        result=divmod(self.__totalItem,self.__peritems) #返回一个包含商和余数的元组,商为总页数
        if result[1]==0:    # 表示可以整除
            return result[0]
        else:
            return result[0]+1  # 数据库总数/页面总数后还有多余的数据,所以总条数还需要加1页来显示剩余的数据


""" 根据基础页链接,当前页,总页数计算出页码显示部分的内容 """
def Custompager(baseurl,currentPage,totalpage):  #基础页,当前页,总页数
perPager=11 # 默认页码数显示范围为11
# if 总页数<11
#0 -- totalpage # 获得从起始页到总页数的范围,end页码数就是根据数据库总页数
# if 总页数>11
# if 当前页>5 获得 currentPage-5 -- currentPage+5的页码数
#currentPage+5是否超过总页数,超过总页数,end就是总页数
# if 当前页< 5  获得 0 -- 11 范围的页码数
# 根据begin,end的范围显示所有的中间页码数
begin=0
end=0
if totalpage <= 11:
begin=0
end=totalpage
else:
if currentPage>5:
begin=currentPage-5
end=currentPage+5
if end > totalpage:
end=totalpage
else:
begin=0
end=11
# 组装页码数显示模块
pager_list=[]
if currentPage<=1:
first="<a href=''>首页</a>"
else:
first="<a href='%s%d'>首页</a>" % (baseurl,1)
pager_list.append(first)

if currentPage<=1:
prev="<a href=''>上一页</a>"
else:
prev="<a href='%s%d'>上一页</a>" % (baseurl,currentPage-1)
pager_list.append(prev)
# 循环中间页,与数据表中的数据显示关联起来
for i in range(begin+1,end+1):
if i == currentPage:    # 当前页选中状态,添加class样式
temp="<a href='%s%d' class='selected'>%d</a>" % (baseurl,i,i)
else:
temp="<a href='%s%d'>%d</a>" % (baseurl,i,i)
pager_list.append(temp)
#
if currentPage>=totalpage:
next="<a href='#'>下一页</a>"
else:
next="<a href='%s%d'>下一页</a>" % (baseurl,currentPage+1)
pager_list.append(next)
# 
if currentPage>=totalpage:
last="<a href=''>末页</a>"
else:
last="<a href='%s%d'>末页</a>" % (baseurl,totalpage)
pager_list.append(last)
result=''.join(pager_list)  # 将列表数据通过拼接转换成字符串
return mark_safe(result)   #把字符串转成html语言
总结,分页时需要做三件事:
创建处理分页数据的类
根据分页数据获取数据
输出分页HTML,即:[上一页][1][2][3][4][5][下一页]

十五、序列化


Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。

serializers模块:对Queryset对象序列化

from django.core import serializers
    ret = models.BookType.objects.all()
    data = serializers.serialize("json", ret)

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字符串

json.dumps时无法处理datetime日期,可通过自定义处理器来做扩展

import json  
from datetime import date  
from datetime import datetime  

class JsonCustomEncoder(json.JSONEncoder): 

    def default(self, field):      
        if isinstance(field, datetime):  # 传入数据类型判断,时间
            return o.strftime('%Y-%m-%d %H:%M:%S')  # 格式化成字符串
        elif isinstance(field, date):  # 日期
            return o.strftime('%Y-%m-%d')  
        else:  
            return json.JSONEncoder.default(self, field)    # 调用父类中的default方法

  # ds = json.dumps(d, cls=JsonCustomEncoder)  # 扩展类的应用范例,d为日期数据
基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip 个人大四的毕业设计、课程设计、作业、经导师指导并认可通过的高分设计项目,评审平均分达96.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 [资源说明] 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设或者课设、作业,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96.5分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),供学习参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值