文档章节

【精华】【学以致用】Django精华总结

Asktao
 Asktao
发布于 2017/10/31 15:23
字数 14502
阅读 135
收藏 5

简单入门和梳理

1、WEB框架

    MVC
        Model       View       Controller
        数据库   模板文件    业务处理
    MTV
        Model    Template     View
        数据库   模板文件    业务处理
    ############## WEB:MVC、MTV

2、Django

    #安装
    pip3 install django
    
    # 创建Django工程
    django-admin startproject 【工程名称】


        mysite
            - mysite        # 对整个程序进行配置
                - init
                - settings  # 配置文件
                - url       # URL对应关系
                - wsgi      # 遵循WSIG规范,uwsgi + nginx
            - manage.py     # 管理Django程序:
                                - python manage.py
                                - python manage.py startapp xx
                                - python manage.py makemigrations
                                - python manage.py migrate
       
    # 运行Django功能
    python manage.py runserver 127.0.0.1:8001

    # 创建app
    python manage.py startapp cmdb
    python manage.py startapp openstack
    python manage.py startapp xxoo....

    # app目录结构
    app:
        migrations     数据修改表结构
        admin          Django为我们提供的后台管理
        apps           配置当前app
        models         ORM,写指定的类  通过命令可以创建数据库结构
        tests          单元测试
        views          业务代码

    1、配置模板的路径

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',
            ],
        },
    },
]


    2、配置静态目录static(    最后一行添加)

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

 

<link rel="stylesheet" href="/static/commons.css" />

        3、app下views.py

def func(request):
    # request.method   GET / POST
    
    # http://127.0.0.1:8009/home?nid=123&name=alex
    # request.GET.get('',None)   # 获取请求发来的而数据
    # request.POST.get('',None)
    
    
    # return HttpResponse("字符串")
    # return render(request, "HTML模板的路径")
    # return redirect('/只能填URL')

    4、模板渲染
            -- {{ 变量名 }}

def func(request):
    return render(request, "index.html", {'current_user': "wangxihao"})
<!-- index.html -->			
<html>
..
<body>
    <div>{{current_user}}</div> <!--显示:wangxihao-->
</body>

</html>

        -- For循环

def func(request):
    return render(request, "index.html", {'current_user': "w1", 'user_list': ['w1','w2']})
<!-- index.html	-->
<html>
..
<body>
    <div>{{current_user}}</div>
    <ul>
    {% for row in user_list %}
        {% if row == "w1" %}
            <li>{{ row }}</li>
        {% endif %}							
    {% endfor %}
    </ul>		
</body>
</html>

#####索引#####

# views
def func(request):
    return render(request, "index.html", {'current_user': "alex", 
			                  'user_list': ['alex','eric'], 
					  'user_dict': {'k1': 'v1', 'k2': 'v2'}})
<!-- index.html -->
<html>
..
<body>
	<div>{{current_user}}</div>					
	<a> {{ user_list.1 }} </a>
	<a> {{ user_dict.k1 }} </a>
	<a> {{ user_dict.k2 }} </a>
</body>
</html>

第二课

    1、Django请求生命周期
        -> URL对应关系(匹配) -> 视图函数 -> 返回用户字符串
        -> URL对应关系(匹配) -> 视图函数 -> 打开一个HTML文件,读取内容

    2、路由系统

  • url(r'^index/', views.index),    
    url(r'^home/', views.Home.as_view()),
  • url(r'^detail-(\d+).html', views.detail),  
  • url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)

           实战1:

url(r'^detail-(\d+)-(\d+).html', views.detail),

def func(request, nid, uid):
    pass

def func(request, *args):
    args = (2,9)

def func(request, *args, **kwargs):
    args = (2,9)

           实战2:

url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)

def func(request, nid, uid):
    pass
    
def funct(request, **kwargs):
    kwargs = {'nid': 1, 'uid': 3}
    
def func(request, *args, **kwargs):
    args = (2,9)

 

  • name
    对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL *****
    url(r'^asdfasdfasdf/', views.index, name='i1'),
    url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'),
    url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'),
    def func(request, *args, **kwargs):
        from django.urls import reverse
        
        url1 = reverse('i1')                              # asdfasdfasdf/
        url2 = reverse('i2', args=(1,2,))                 # yug/1/2/
        url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/
    <!-- xxx.html -->
    {% url "i1" %}               # asdfasdfasdf/
    {% url "i2" 1 2 %}           # yug/1/2/
    {% url "i3" pid=1 nid=9 %}   # buy/1/9/

    PS:当前的URL----request.path_info

  • 默认值

    # urls
    url(r'^index/', views.index, {'name': 'root'}),
    		
    # views
    def index(request,name):
        print(name)
        return HttpResponse('OK')

    **这里没有完全弄明白~
    一种传递参数的方式。呵呵

  • 命名空间

    /admin/    include('app01.urls',namespace='m1')
    /crm/      include('app01.urls',namespace='m2')
    			
    app01.urls
    /index/(?P<arg1>\d+)    name = 'n1'
    			
    # 通过namespace:name,反向生成URL
    reverser('m1:n1' kwargs={'arg1':11})    # /admin/index/11
    reverser('m2:n1')                       # /crm/index
    
    # 模板语言下的reverser
    {% url 'm1:n1' arg1=11 %}    # /admin/index/11

    **这里没有完全弄明白~   
    使用reverser的方法,解决调用同一views函数时,路径的区分问题。基本用不到。呵呵
     

    3、视图

        1、获取用户请求数据
            request.body  # 所有内容的原始值
                request.GET
                request.POST
                request.FILES
                request.xxxx.getlist
            request.meta  # 请求头相关的内容
                request.COOKIES
                request.path_info
                request.method

 

        PS:
            GET:获取数据                
            POST:提交数据
            
        2、checkbox等多选的内容
            request.POST.getlist()


        3、上传文件

# 上传文件,form标签做特殊设置
obj = request.FILES.get('fafafa')
obj.name    //取文件名
obj.size    //取文件大小
//obj.chunks()  //取文件
f = open(obj.name, mode='wb')
for item in obj.chunks():
    f.write(item)
f.close()

  HTML中表单的特殊设置

<form action="{% url "url" %}" method="post" enctype="multipart/form-data">
<!-- form特殊设置:enctype="multipart/form-data" -->
</form>


        4、FBV & CBV
            function base view

def index(request,*args,**kwargs):
    if request.method == "POST":
        pass
    else request.method == "GET":
        pass

            class base view

from django.view import View

class Home(View):
    def get(self,reqeust,*args,**kwargs):
        pass

            建议:两者都用
       订制CBV

from django.view import View

Class Foo(View):
    # 每次在执行Foo 方法时,可以自定义,之前和之后的操作
    def dispatch(self,request):
        print("before")
        result = super(Foo,self).dispatch(request,*args,**kwargs)
        print("after")
        return result

    def get(self,request):
        print("get get get")
        return Httprespone("get OK")

    def post(self,request):
        print("post post post")
        return Httprespone("post OK")


        5、装饰器

            FBV的装饰器

def auth(func):
    def inner(reqeust,*args,**kwargs):
    v = reqeust.COOKIES.get('username111')
        if not v:
            return redirect('/login/')
        return func(reqeust, *args,**kwargs)
    return inner

@auth
def home(request):
    u = request.COOKIES.get("username")
    psw = request.COOKIES.get("psw")
    return render(reqeust,'index.html',{'current_user': v})

            CBV的装饰器

from django import views
from django.utils.decorators import method_decorator

@method_decorator(auth,name='dispatch')    # 同2、给这个class的所有的方法增加装饰器的另一种方法
class Order(views.View):

# @method_decorator(auth)    # 2、给这个class中所有的方法增加装饰器
# def dispatch(self, request, *args, **kwargs):
#     return super(Order,self).dispatch(request, *args, **kwargs)

# @method_decorator(auth)    # 1、单独给一个方法提供装饰器
def get(self,reqeust):
    v = reqeust.COOKIES.get('username111')
    return render(reqeust,'index.html',{'current_user': v})

def post(self,reqeust):
    v = reqeust.COOKIES.get('username111')
    return render(reqeust,'index.html',{'current_user': v})

# 回顾一下,CBV的书写方式。
# urls.py
# url('/order/',views.order.as_views)

                6、请求的其他信息

# views

def index(request):
    print(request.environ)     # environ 存放所有的请求信息

    # 除了request.environ以外所有的子方法,都是django封装的。
    print(request.POST)
    print(request.GET)
    print(request.METHOD)
    print(request.FILE)

    for v,k in request.environ.items():
        print(v,k)             # 查看environ所有的信息

    # 查看访问的客户端信息
    print(request.environ['HTTP_USER_AGENT'])

    3、模板
        3.1、模板的继承(母版block)

<!-- 母版HTML -->
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link href="公用的.css" rel="stylesheet" type="text/css" />
    {% block pir_css %}{% endblock %} <!-- 引用模块私有的class -->
</head>
<body>
    {% block someCode %}{% endblock %}

    <script src="jquery.js"></script>
    {% block pir_js %}{% endblock %} <!-- 引用模块私有的js-->
</body>
</html>
{% extends '母版.html' %}

<!-- 子版1.HTML -->  <!-- 子版2.html同样-->
{% block pir_css %}
    <link href="someCode.css" rel="stylesheet" type="text/css" /> 
{% endblock %}

{% block someCode %}
<h1> block后面的 someCode 要对应母版的名字。 <h1>
{{ someCode }}<!-- 这是后台传递过来的数据 -->
{% endblock %}

{% block pir_js %}
<script>
alert('这个页面继承了母版HTML')
</script>
{% endblock %}
# urls.py
from django.conf.urls import url,
from cmdb import views
urlpatterns = [
    url(r'^cmdb/$', views.index1),
    url(r'^cmdb/$', views.index2),
]

# views
def index1(request):
    return render(request,"子版1.html",{"someCode":"<div>HELLO WORLD!!</div>","OTHER":['other1','other2','other3']})

def index2(request):
    return render(request,"子版2.html",{"someCode":"<div>HELLO PYTHON!!</div>","OTHER":[111,222,333]})

        3.2、模板的导入

{% extends '母版.html' %}

<!-- 延用3.1、继承的代码,稍作修改。 -->

<!-- 子版1.HTML -->  <!-- 子版2.html同样-->
{% block pir_css %}
    <link href="someCode.css" rel="stylesheet" type="text/css" /> 
{% endblock %}

{% block someCode %}
<h1> block后面的 someCode 要对应母版的名字。 <h1>
{{ someCode }}<!-- 这是后台传递过来的数据 -->

<!-- 添加要引入的代码 -->
{% include 'tag.html '%}

{% endblock %}

{% block pir_js %}
<script>
alert('这个页面继承了母版HTML')
</script>
{% endblock %}
<!-- tag.html -->

<!-- 被引入的小模板,同样可以被上级页面渲染 -->
<div>{{ title }}</div>
<ul>
  {% for x in other %}
    <li>{{x}}</li>
  {% endfor %}
</ul>

        3.3、自定义模板

        3.3.1、simple_tag

a. app下创建templatetags目录
b. 任意xxoo.py文件
c. 创建template对象 register
d. 
    @register.simple_tag
    def func(a1,a2,a3....)
        return "asdfasd"
e. settings中注册APP
f. 顶部 {% load xxoo %}
g. {% 函数名 arg1 arg2 %}

缺点:
    不能作为if条件
优点:
    参数任意

        3.3.2、filter

a. app下创建templatetags目录
b. 任意xxoo.py文件
c. 创建template对象 register
d. 
    @register.filter
    def func(a1,a2)
        return "asdfasd"
e. settings中注册APP
f. 顶部 {% load xxoo %}
g. {{ 参数1|函数名:"参数二,参数三" }} {{ 参数1|函数名:数字 }}

缺点:
    最多两个参数,不能加空格
优点:
    能作为if条件

    3.3.3、分页
        1、XSS攻击,默认DJango后台传递不安全。解决办法:
            1.1,前端模板使用

{{str | safe}}

            1.2、后端使用

from django.utils.safestring import make_safe

def index(request):
    str = "<h1>haha</h1>"
    str = make_safe(str)
    return render(request,"index.html",{"str1":str1})

        2、具体rerr代码

from django.utils.safestring import mark_safe


class Page:
    def __init__(self, current_page, data_count, per_page_count=10, pager_num=7):
        self.current_page = current_page
        self.data_count = data_count
        self.per_page_count = per_page_count
        self.pager_num = pager_num

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_count

    @property
    def end(self):
        return self.current_page * self.per_page_count

    @property
    def total_count(self):
        v, y = divmod(self.data_count, self.per_page_count)
        if y:
            v += 1
        return v

    def page_str(self, base_url):
        page_list = []

        if self.total_count < self.pager_num:
            start_index = 1
            end_index = self.total_count + 1
        else:
            if self.current_page <= (self.pager_num + 1) / 2:
                start_index = 1
                end_index = self.pager_num + 1
            else:
                start_index = self.current_page - (self.pager_num - 1) / 2
                end_index = self.current_page + (self.pager_num + 1) / 2
                if (self.current_page + (self.pager_num - 1) / 2) > self.total_count:
                    end_index = self.total_count + 1
                    start_index = self.total_count - self.pager_num + 1

        if self.current_page == 1:
            prev = '<a class="page" href="javascript:void(0);">上一页</a>'
        else:
            prev = '<a class="page" href="%s?p=%s">上一页</a>' % (base_url, self.current_page - 1,)
        page_list.append(prev)

        for i in range(int(start_index), int(end_index)):
            if i == self.current_page:
                temp = '<a class="page active" href="%s?p=%s">%s</a>' % (base_url, i, i)
            else:
                temp = '<a class="page" href="%s?p=%s">%s</a>' % (base_url, i, i)
            page_list.append(temp)

        if self.current_page == self.total_count:
            nex = '<a class="page" href="javascript:void(0);">下一页</a>'
        else:
            nex = '<a class="page" href="%s?p=%s">下一页</a>' % (base_url, self.current_page + 1,)
        page_list.append(nex)

        jump = """
        <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
        <script>
            function jumpTo(ths,base){
                var val = ths.previousSibling.value;
                location.href = base + val;
            }
        </script>
        """ % (base_url,)

        page_list.append(jump)

        page_str = mark_safe("".join(page_list))

        return page_str

        3、具体分页调用方法

from utils import pagination # 导入上面的代码

LIST = []               # 模拟数据
for i in range(500):    # 模拟数据
    LIST.append(i)      # 模拟数据

def user_list(request):
    current_page = request.GET.get('p', 1)
    current_page = int(current_page)

    page_obj = pagination.Page(current_page,len(LIST),val)

    data = LIST[page_obj.start:page_obj.end]

    page_str = page_obj.page_str("/user_list/")

    return render(request, 'user_list.html', {'li': data,'page_str': page_str})

模板语言的取值:   

render(
    request,
    "xxx.html",
    {
    'obj':1234,
    'k1':[1,2,3,4],
    'k2':{'name':'www','age':77}
    }
)

  HTML模板的取值:

<html>

<body>
<!-- 取单独的值 -->
<p>{obj}</p>
<p>{k1.3}列表</p>
<p>{k2.name}字典</p>

<!-- 遍历所有值 -->
{% for i in k1 %}
    <p>{{i}}</p>
{% endfor %}

{% for row in k2,keys %}
    <p>{{row}}</p>
{% endfor %}

{% for row in k2.value %}
    <p>{{row}}</p>
{% endfor %}

{% for k,v in k2.items %}
    {% forloop.counter # 正序循环次数的计数器从1开始 %}
    {% forloop.counter0 # 正序循环次数的计数器从0开始 %}
    {% forloop.revcounter # 倒叙循环次数的计数器从开始 %}
    {% forloop.revcounter0 # 倒叙循环次数的计数器从0开始 %}

    {% forloop.frist # 判断是否是第一次循环 %}
    {% forloop.last # 判断是否是最后一次循环 %}

    {% forloop.parentloop# 显示父循环的次数,需要有父层循环 %}

    <p>{{k}}---{{v}}</p>
{% endfor %}

</body>
</html>

  4、ORM操作

select * from tb where id > 1
# 对应关系
models.tb.objects.filter(id__gt=1)
models.tb.objects.filter(id=1)
models.tb.objects.filter(id__lt=1)

        4.1、创建类
        ----先写类:

from django.db import models

# app01_userinfo
class UserInfo(models.Model):
    # id列,自增,主键
    # 用户名列,字符串类型,指定长度
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)

    ----注册APP(settings.py)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01',
]

    ----执行命令

python manage.py  makemigrations
python manage.py  migrate

   ********** 注意 ***********
        Django默认使用MySQLdb模块链接MySQL
        主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可:

pip install pymysql
import pymysql
pymysql.install_as_MySQLdb()

        4.2、字段

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

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

    注:当model中如果没有自增列,则自动会创建一个列名为id的列
    from django.db import models

    class UserInfo(models.Model):
        # 自动创建一个列名为id的且为自增的整数列
        username = models.CharField(max_length=32)

    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

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正整数 0 ~ 2147483647

BigIntegerField(IntegerField):
    - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807


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)
    - 二进制类型
自定义无符号整数字段

    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)',
# 注意事项
    1.触发Model中的验证和错误提示有两种方式:
        a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
        b. 使用ModelForm
        c. 调用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):
            age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'})

            class Meta:
                model = models.UserInfo
                # fields = ('username',)
                fields = "__all__"
                exclude = ['title']
                labels = { 'name':'Writer', }
                help_texts = {'name':'some useful help text.',}
                error_messages={ 'name':{'max_length':"this writer name is too long"} }
                widgets={'name':Textarea(attrs={'cols':80,'rows':20})}

        class UserInfoAdmin(admin.ModelAdmin):
            form = UserInfoForm

        admin.site.register(models.UserInfo, UserInfoAdmin)

        4.3、字段的参数

    null                数据库中字段是否可以为空
    db_column           数据库中字段的列名
    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中显示的表名称+s
            verbose_name

            # verbose_name 不加5
            verbose_name_plural

       4.4、操作ORM

# 增
models.User.objects.create(name='qianxiaohu',age=18)

dic = {'name': 'xx', 'age': 19}
models.User.objects.create(**dic)

obj = models.User(name='qianxiaohu',age=18)
obj.save()
# 删
models.User.objects.filter(id=1).delete()
# 改
models.User.objects.filter(id__gt=1).update(name='xxx',age=84)
dic = {'name': 'xx', 'age': 19}
models.User.objects.filter(id__gt=1).update(**dic)

obj = models.Tb1.objects.get(id=1)
obj.c1 = '111'
obj.save() 
# 查
models.User.objects.filter(id=1,name='root')
models.User.objects.filter(id__gt=1,name='root')
models.User.objects.filter(id__lt=1)
models.User.objects.filter(id__gte=1)
models.User.objects.filter(id__lte=1)

models.User.objects.filter(id=1,name='root')
dic = {'name': 'xx', 'age__gt': 19}
models.User.objects.filter(**dic)

v1 = models.Business.objects.all()                              # QuerySet ,内部元素都是对象
v2 = models.Business.objects.all().values('id','caption')       # QuerySet ,内部元素都是字典
v3 = models.Business.objects.all().values_list('id','caption')  # QuerySet ,内部元素都是元组

models.Business.objects.get(id=1)               # 获取到的一个对象,如果不存在就报错
models.Business.objects.filter(id=1).first()    # 获得对象或者None,不存在也不会报错
# 获取个数
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的值

# in
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

# isnull
Entry.objects.filter(pub_date__isnull=True)

# contains  --类似sql的like操作
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'))
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) +')
Entry.objects.get(title__iregex=r'^(an?|the) +')

# date
Entry.objects.filter(pub_date__date=datetime.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)


# 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)


# 执行原生SQL

from django.db import connection, connections
cursor = connection.cursor()  # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone()

 

##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################

def all(self)
    # 获取所有的数据对象

def filter(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def exclude(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def select_related(self, *fields)
     性能相关:表之间进行join连表操作,一次性获取关联的数据。
     model.tb.objects.all().select_related()
     model.tb.objects.all().select_related('外键字段')
     model.tb.objects.all().select_related('外键字段__外键字段')

def prefetch_related(self, *lookups)
    性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
            # 获取所有用户表
            # 获取用户类型表where id in (用户表中的查到的所有用户ID)
            models.UserInfo.objects.prefetch_related('外键字段')



            from django.db.models import Count, Case, When, IntegerField
            Article.objects.annotate(
                numviews=Count(Case(
                    When(readership__what_time__lt=treshold, then=1),
                    output_field=CharField(),
                ))
            )

            students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                models.Case(
                    models.When(absence__type='Excused', then=1),
                default=0,
                output_field=models.IntegerField()
            )))

def annotate(self, *args, **kwargs)
    # 用于实现聚合group by查询

    from django.db.models import Count, Avg, Max, Min, Sum

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用于distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    注:只有在PostgreSQL中才能使用distinct进行去重

def order_by(self, *field_names)
    # 用于排序
    models.UserInfo.objects.all().order_by('-id','age')

def 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'])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    或
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列数据

 def only(self, *fields):
    #仅取某个表中的数据
     models.UserInfo.objects.only('username','id')
     或
     models.UserInfo.objects.filter(...).only('username','id')

 def using(self, alias):
     指定使用的数据库,参数为别名(setting中的设置)


##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################

def raw(self, raw_query, params=None, translations=None, using=None):
    # 执行原生SQL
    models.UserInfo.objects.raw('select * from userinfo')

    # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
    models.UserInfo.objects.raw('select id as nid from 其他表')

    # 为原生SQL设置参数
    models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])

    # 将获取的到列名转换为指定列名
    name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

    # 指定数据库
    models.UserInfo.objects.raw('select * from userinfo', using="default")

    ################### 原生SQL ###################
    from django.db import connection, connections
    cursor = connection.cursor()  # cursor = connections['default'].cursor()
    cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    row = cursor.fetchone() # fetchall()/fetchmany(..)


def values(self, *fields):
    # 获取每行数据为字典格式

def values_list(self, *fields, **kwargs):
    # 获取每行数据为元祖

def dates(self, field_name, kind, order='ASC'):
    # 根据时间进行某一部分进行去重查找并截取指定内容
    # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    # order只能是:"ASC"  "DESC"
    # 并获取转换后的时间
        - year : 年-01-01
        - month: 年-月-01
        - day  : 年-月-日

    models.DatePlus.objects.dates('ctime','day','DESC')

def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
    # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
    # kind只能是 "year", "month", "day", "hour", "minute", "second"
    # order只能是:"ASC"  "DESC"
    # tzinfo时区对象
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))

    """
    pip3 install pytz
    import pytz
    pytz.all_timezones
    pytz.timezone(‘Asia/Shanghai’)
    """

def none(self):
    # 空QuerySet对象


####################################
# METHODS THAT DO DATABASE QUERIES #
####################################

def aggregate(self, *args, **kwargs):
   # 聚合函数,获取字典类型聚合结果
   from django.db.models import Count, Avg, Max, Min, Sum
   result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
   ===> {'k': 3, 'n': 4}

def count(self):
   # 获取个数

def get(self, *args, **kwargs):
   # 获取单个对象

def create(self, **kwargs):
   # 创建对象

def bulk_create(self, objs, batch_size=None):
    # 批量插入
    # batch_size表示一次插入的个数
    objs = [
        models.DDD(name='r11'),
        models.DDD(name='r22')
    ]
    models.DDD.objects.bulk_create(objs, 10)

def get_or_create(self, defaults=None, **kwargs):
    # 如果存在,则获取,否则,创建
    # defaults 指定创建时,其他字段的值
    obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})

def update_or_create(self, defaults=None, **kwargs):
    # 如果存在,则更新,否则,创建
    # defaults 指定创建时或更新时的其他字段
    obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})

def first(self):
   # 获取第一个

def last(self):
   # 获取最后一个

def in_bulk(self, id_list=None):
   # 根据主键ID进行查找
   id_list = [11,21,31]
   models.DDD.objects.in_bulk(id_list)

def delete(self):
   # 删除

def update(self, **kwargs):
    # 更新

def exists(self):
   # 是否有结果

数据库操作--QuerySet中方法:

- QuerySet中的方法:
    - 返回QuerySet类型(select_related,prefetch_related)
        
        select_related
        # 一次完成参数内的跨表查询,如果需要跨其他表,则再发起一次请求。
            users = models.User.objects.all().select_related('ut')
            for row in users:
                print(row.user,row.pwd,row.ut_id)
                print(row.ut.name)
                print(row.tu.name) # 再发起一次SQL请求
        
        prefetch_related
            
            users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu')
            # select * from users where id > 30
            # 获取上一步骤中所有的ut_id=[1,2]
            # select * from user_type where id in [1,2]
            # select * from user_type where id in [1,2]
            
            for row in users:
                print(row.user,row.pwd,row.ut_id)
                print(row.ut.name)

多表关系以及参数

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(ForeignKey)
    to,                         # 要进行关联的表名
    to_field=None               # 要关联的表中的字段名称
    on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为

                                ###### 对于一对一 ######
                                # 1. 一对一其实就是 一对多 + 唯一索引
                                # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
                                # 如下会在A表中额外增加一个c_ptr_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(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)
                                        - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
    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,              # 默认创建第三张表时,数据库中表的名称
# 外键:
class UserType(models.Model):
    caption = models.CharField(max_length=32)
# id  caption
# 1,普通用户
# 2,VIP用户
# 3, 游客

class User(models.Model):
    age = models.IntergerFiled()
    name = models.CharField(max_length=10)#字符长度
    # user_type_id = models.IntergerFiled() # 约束,
    user_type = models.ForeignKey("UserType",to_field='id') # 约束,

# name age  user_type_id
# 张扬  18     3
# 张A扬 18     2
# 张B扬 18     2

#外键:
v = models.User.objects.filter(nid__gt=0)
v[0].user_type.caption  ---->  通过.进行跨表

        4.5、AJAX

$.ajax({
    url: '/host',
    type: "POST",
    data: {'k1': 123,'k2': "root"},
    //data:{'k1':123,'list':[1,2,3,4]},
    //traditional:true,    //这个属性表示,可以传递列表

    //processData:false,    //JQ上传文件时,设置不做特殊处理。
    //contentType:false,    //JQ上传文件时,设置不做特殊处理。

    //后台取值的时候使用 request.POST.getlist("list")  
    //格式,["1","2","3","4"]
    success: function(data){
        // data是服务器端返回的字符串
        var obj = JSON.parse(data);
    }
})

   建议:永远让服务器端返回一个字典

# views
 return HttpResponse(json.dumps(字典))

    4.6、一对多 and 正向操作 and 反向操作

def func():
    # User类中,on_delete=models.SET(func)的回调函数
    return 5


class UserType(models.Model):
    name = models.CharField(max_length=32)
    

class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    ....         ForiegnKey(to="UserType",to_field='id',on_delete=models.SET(func))

# delete from user where id=1
# delete from UserType where id=1 # 报错,因为User表中有数据正在使用UserType,所以会报错。

# UserType.objects.filter(id=1).delete()    # 在新版django中,不再报错,直接删除,并连带User表中的关联数据一起删除 
# 参考model创建表时的,on_delete方法进行设置。



# 正向 ---从User表中操作UserType
# v = User.objects.all()
# for item in v:
#     item.user
#     item.pwd
#     item.ut.name

# User.objects.all().values('user','ut__name')


# 反向  ---从UserType表中操作User
# v = UserType.objects.all()
# for item in v:
#     item.name
#     item.id
#     item.user_set.all()    # 如果在foreignKey(related_name=b),则 item.b.all()
                             # 如果在foreignKey(related-query_name=a),则 item.a_set.all() 
# models.UserType.objects.all().values('name','user__pwd')
# 如果在foreignKey(related_name=b)
# models.UserType.objects.all().values('b')

# 如果在foreignKey(related-query_name=a)
# models.UserType.objects.all().values('name','a__pwd')

    4.7、创建多对多

            方式一:自定义关系表

class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field='id')
# 10
class Application(models.Model):
    name = models.CharField(max_length=32)
# 2

class HostToApp(models.Model):
    hobj = models.ForeignKey(to='Host',to_field='nid')
    aobj = models.ForeignKey(to='Application',to_field='id')

# HostToApp.objects.create(hobj_id=1,aobj_id=2)

            方式二:自动创建关系表

class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field='id')
# 10
class Application(models.Model):
    name = models.CharField(max_length=32)
    r = models.ManyToManyField("Host")
    
#无法直接对第三张表进行操作

obj = Application.objects.get(id=1)
obj.name

# 第三张表操作
obj.r.add(1)
obj.r.add(2)
obj.r.add(2,3,4)
obj.r.add(*[1,2,3,4])

obj.r.remove(1)
obj.r.remove(2,4)
obj.r.remove(*[1,2,3])

obj.r.clear()

obj.r.set([3,5,7])

# 所有相关的主机对象“列表” QuerySet
obj.r.all()

# 筛选,筛选出主机名为c1的主机
obj.r.filter(hostname="c1")

    4.8、数据验证(偏弱)

# 这句话执行了,email就保存了1234156,尽管不合规。
models.tb.objects.create(user=name,email="1234156")

# 这句话执行了,email就保存了1234156,尽管不合规。
obj = models.tb(user=name,email="1234156")
obj.save()

# 这里就出现了验证功能。
obj = models.tb(user=name,email="1234156")
obj.full_clean()    # 执行这句的时候,验证正则规则。如果不合规,就报错了。错误类型是ValidationError
obj.save()

# ValidationError  引申一下。
# 这里有一个钩子,虽然不知道有什么用。
# xx.full_clean()中有一个方法叫做self.clean(),里面是代码是pass。而这个clean就是所谓的钩子。
# 在执行正则验证之后,都会再执行一次clean方法。尽管现在是空的,但我们可以做些东西。

#models.py
class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

    def clean(self):
        # 这里有进行了一次数据库操作,当然可以自定义其他操作。
        c = UserInfo.objects.filter(name=self.name).count()
        if c:
            from django.core.exceptions import ValidationError
            rasie ValidationError(message="用户名已存在",code="exist")
            # 只能是ValidationError错误哦

# 尽管验证功能,还是让验证模块去做最好了。所以只是知道一下就好了。

 

5、cookie

    5.1、cookie 是什么?
            cookie,是客户端上的浏览器储存一个文件。字典格式的。浏览器访问时会将本地的cookie发送的服务器。
            接收方式是

request.COOKIES
request.COOKIES.get("username")
request.COOKIES["username"]

# 加密传输cookie
request.get_signed_cookie("username", "kangbazi",salt="基于salt加密")

            设置cookie的方式

rep = HttpResponse(...) 或 rep = render(request, ...)
rep['name'] = "WXH"    # 给响应头中添加数据(ResponseHeader)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
    参数:
        key,              键
        value='',         值
        max_age=None,     超时时间 -- 参数分钟秒,倒计时
        expires=None,     超时时间(datetime格式)
        path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
        domain=None,      Cookie生效的域名
        secure=False,     https传输
        httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

            JS也可以操作cookie

<script src="/static/jq.cookie.js"></script>
<script>
//获取cookie
$.cookie("key")

//设置cookie
$.cookie("key","value",{"path":"/home"})

//其他参数参考django设置cookie的方式
</script>

6、session

    6.1、session的原理
            session是保存的在服务器端的键值对
            session是基于cookie的

    6.2、Session配置(缺少cache)

# settings.py

# 配置文件中设置默认操作(通用配置):
SESSION_COOKIE_NAME = "sessionid"              # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/"                	# Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None                	# Session的cookie保存的域名(默认)
ESSION_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,默认修改之后才保存(默认)

    6.3、session的5种类型。

        6.3.1、数据库(默认)

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_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,默认修改之后才保存(默认)
 
 
 
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失效策略。

        6.3.2、缓存

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,默认修改之后才保存
 
 
 
b. 使用
 
    同上

        6.3.3、文件

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,默认修改之后才保存
 
b. 使用
 
    同上

        6.3.4、缓存+数据库

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

        6.3.5、加密cookie

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

       6.4、 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

 

7、CSRF-跨站请求伪造

    7.1、CSRF原理
        7.1.0、盗取Cookie,伪装登录,为所欲为。
        7.1.1、form添加 {% csrf_token %}
        7.1.2、django会在加载HTML时生成一个随机字符串,保存到cookie中。
        7.1.3、在页面POST提交时,同时会把这个随机字符串提交到服务器。或者在cookie中让django获取。
        7.1.4、获取的随机字符串与django本地的随机字符串做比较,来判断是否阻止页面提交。达到防止跨站请求伪造。
    7.2、Form提交(CSRF)

<form action='/login/' method='post'>
    {% csrf_token %}
    <input type='text' name='user' />
    <input type='password' name='pwd' />
    <input type='submit' value='提交' />
</form>
<!-- 只需要加入 {% csrf_token %} 即可 -->
<!-- 随机字符串保存在cookie中 -->

    7.3、Ajax提交(CSRF)
            CSRF请求头 X-CSRFToken

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% csrf_token %}
  
    <input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
    <script type="text/javascript">
        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);
                }
            }
        });
        function Do(){
  
            $.ajax({    //ajax的全局配置
                url:"/app01/test/",
                data:{id:1},
                type:'POST',
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>
</body>
</html>

    7.4、CSRF的全局与个例

# 全局:
# 在settings.py 中 注释或者不注释-中间件 
django.middleware.csrf.CsrfViewMiddleware

# 局部:
# 在单独的views中的方法,添加装饰器。

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

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

8、中间件

    中间件,也叫管道。在 setting.py 中的 MIDDLEWARE_CLASSES 声明。

    中间件的作用是,请求触发之后,现在进入中间件,在进入url.py。离开时,最后执行中间件。

    中间件是一个类,继承 middlewareMixin。比如CsrfViewMiddleware(MiddlewareMixin)
    值得一说的是,MiddlewareMixin方法中有两个重要的方法。

    process_requestprocess_response  

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

    如何写一个中间件?

    1、创建一个中间件的类,并继承MiddlewaveMixin

from django.utils.deprecation import MiddlewareMixin

class MiddlewaveRow1(MiddlewareMixin):

    # process_request:访问时触发
    def process_request(self,request):
        print('MiddlewaveRow1--process_reques')

    # process_response:离开(返回)时触发
    def process_response(self,request,response):
        print('MiddlewaveRow1--process_response')
        return response

class MiddlewaveRow2(MiddlewareMixin):

    # process_request:访问时触发
    def process_request(self,request):
        print('MiddlewaveRow2--process_reques')

    # process_response:离开(返回)时触发
    def process_response(self,request,response):
        print('MiddlewaveRow2--process_response')
        return response

    2、将创建的中间件加载到中间件池子中。

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',
    'Middlewave_pool.MiddlewavePool.MiddlewaveRow1',
    'Middlewave_pool.MiddlewavePool.MiddlewaveRow2',
]

    3、随便访问一个页面吧,再回到IDE看控制台输出的信息。

    4、中间件引申一下,如果在中间件process_request方法中,添加return方法。则,直接从当前中间件的process_response方法向出站方向执行。
        不会进入下一个中间件,也不会进入url.py

    5、中间件的另外3种方法:
        process_view(self,request,xx_view,xx_args,xx_kwargs)
        此方法是在所有process_request执行完成后,读取url列表,获取view(不执行)
        注:xx_view 是url指向的view方法。
        注:xx_args 是url指向的view方法的默认参数。        例如,url(r'test/(\d+)',views.test)   ,xx_args就是(\d+)
        注:xx_kwargs 是url指向的view方法的指名参数。    例如,url(r'test/(?P<nid>(\d+))',views.test)   ,xx_kwargs就是{nid:(\d+)}

        process_exception(self,request,excepton)
        此方法默认不执行,只有在views执行报错时在触发。
        注:excepton中存放的就是views的错误信息。

        process_template_response(self,request,response)
        此方法默认不执行,只有在返回时,使用render方法时才会触发。    
        注:然并卵……

    6、中间件的声明周期
   

        补充:

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

# 第一次进来时,只有request,穿过所有中间层,取得views方法和views参数后,离开。
process_request(self,request)

# 第二次带着views方法和参数,再走一遍中间件。中间可以处理一些事情了。
process_view(self, request, callback, callback_args, callback_kwargs)
# 到这里,process_request和process_view不能有return,否则直接跳转到process_response

#只有在离开时使用render()方法,才会触发。
process_template_response(self,request,response)

# 页面报错时,在这里处理错误。
process_exception(self, request, exception)

# 页面正常返回时,在这里定制需求。
process_response(self, request, response)

9、缓存

    Django中提供了5种缓存方式:

    1、开发调试

    # 此为开始调试用,实际内部不做任何操作
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
                'TIMEOUT': 300,                                               # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
                'OPTIONS':{
                    'MAX_ENTRIES': 300,                                       # 最大缓存个数(默认300)
                    'CULL_FREQUENCY': 3,                                      # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
                },
                'KEY_PREFIX': '',                                             # 缓存key的前缀(默认空)
                'VERSION': 1,                                                 # 缓存key的版本(默认1)
                'KEY_FUNCTION' 函数名                                          # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
            }
        }


    # 自定义key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func

    2、内存

    # 此缓存将内容保存至内存的变量中
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                'LOCATION': 'unique-snowflake',
            }
        }

    # 注:其他配置同开发调试版本

    3、文件

    # 此缓存将内容保存至文件
    # 配置:

        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
                'LOCATION': '/var/tmp/django_cache',
            }
        }
    # 注:其他配置同开发调试版本

    4、数据库

    # 此缓存将内容保存至数据库

    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
                'LOCATION': 'my_cache_table', # 数据库表
            }
        }

    # 注:执行创建表命令 python manage.py createcachetable

    5、Memcache缓存(python-memcached模块)

# 此缓存使用python-memcached模块连接memcache

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': 'unix:/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }

    6、Memcache缓存(pylibmc模块)

    # 此缓存使用pylibmc模块连接memcache
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }

    缓存的应用三种应用:

    1、全站

   使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存

    MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其他中间件...
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

    CACHE_MIDDLEWARE_ALIAS = ""
    CACHE_MIDDLEWARE_SECONDS = ""
    CACHE_MIDDLEWARE_KEY_PREFIX = ""

    2、单独视图

    方式一:
        from django.views.decorators.cache import cache_page

        @cache_page(60 * 15)
        def my_view(request):
            ...

    方式二:
        from django.views.decorators.cache import cache_page

        urlpatterns = [
            url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
        ]

    3、局部模板

    a. 引入TemplateTag

        {% load cache %}

    b. 使用缓存

        {% cache 5000 缓存key %}
            缓存内容
        {% endcache %}

10、内置信号和自定义信号

    内置信号:

Model signals
    pre_init                    # django的modal执行其构造方法前,自动触发
    post_init                   # django的modal执行其构造方法后,自动触发
    pre_save                    # django的modal对象保存前,自动触发
    post_save                   # django的modal对象保存后,自动触发
    pre_delete                  # django的modal对象删除前,自动触发
    post_delete                 # django的modal对象删除后,自动触发
    m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
Request/response signals
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发
    got_request_exception       # 请求异常后,自动触发
Test signals
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
Database Wrappers
    connection_created          # 创建数据库连接时,自动触发

    对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception

from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed

from django.db.models.signals import pre_migrate, post_migrate
from django.test.signals import setting_changed
from django.test.signals import template_rendered
from django.db.backends.signals import connection_created


def callback(sender, **kwargs):
    print("xxoo_callback")
    print(sender,kwargs)

xxoo.connect(callback)
# xxoo指上述导入的内容
from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

    自定义信号:

        1、定义信号

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

        2、注册信号

def callback(sender, **kwargs):
    print("callback")
    print(sender,kwargs)
 
pizza_done.connect(callback)

        3、触发信号

from 路径 import pizza_done
 
pizza_done.send(sender='seven',toppings=123, size=456)

11、FORM操作

    Django的Form主要具有一下几大功能:

  • 生成HTML标签
  • 验证用户数据(显示错误信息)
  • HTML Form提交保留上次提交数据
  • 初始化页面显示内容                                                               

    11.1、小试牛刀
            创建form

from django.forms import Form
from django.forms import widgets
from django.forms import fields
 
class MyForm(Form):
    user = fields.CharField(
        widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
    )
 
    gender = fields.ChoiceField(
        choices=((1, '男'), (2, '女'),),
        initial=2,
        widget=widgets.RadioSelect
    )
 
    city = fields.CharField(
        initial=2,
        widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
    )
 
    pwd = fields.CharField(
        widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

            views

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        obj = MyForm()
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        obj = MyForm(request.POST, request.FILES)
        if obj.is_valid():
            values = obj.clean()
            print(values)
        else:
            errors = obj.errors
            print(errors)
        return render(request, 'index.html', {'form': obj})
    else:
        return redirect('http://www.google.com')

            HTML

<form action="/" method="POST" enctype="multipart/form-data">
    <p>{{ form.user }} {{ form.errors.user.0 }}</p>
    <p>{{ form.gender }} {{ form.errors.gender.0 }}</p>
    <p>{{ form.city }} {{ form.errors.city.0 }}</p>
    <p>{{ form.pwd }} {{ form.errors.pwd.0 }}</p>
    <input type="submit"/>
</form>

        其他form标签

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}

        {{ form.xxoo.label }}
        {{ form.xxoo.id_for_label }}
        {{ form.xxoo.label_tag }}
        {{ form.xxoo.errors }}
        <p>{{ form.user }} {{ form.user.errors.0 }}</p>

        {{ form.as_p }}
        {{ form.as_ul }}
        <table>{{ form.as_table }}</table>
        <input type="submit" />
</form>

    11.2、Form类
        创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

        Django内置字段如下:

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀
 
 
CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白
 
IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
BaseTemporalField(Field)
    input_formats=None          时间格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允许空文件
 
ImageField(FileField)      
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值
 
ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...
 
UUIDField(CharField)           uuid类型
    ...

        注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串

        Django内置插件:

# from django.forms import widgets
# class MyForm(Form):
#     user = fields.CharField(
#         widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
#     )

# widgets.xxoo  xxoo就是对应以下HTML标签的生成器。

TextInput(Input)                    # type="text"
NumberInput(TextInput)              # type="number"
EmailInput(TextInput)               # type="email"
URLInput(TextInput)                 # type="url"
PasswordInput(TextInput)            # type="password"
HiddenInput(TextInput)              # type="hidden",隐藏的输入
Textarea(Widget)                    # 文本域,textarea标签
DateInput(DateTimeBaseInput)        # type="text",带有可选参数format('%Y年%m月%d日,%b缩写月,%B全拼月')
DateTimeInput(DateTimeBaseInput)    # type="text",带有可选参数format('%y两位年-%Y-%m-%d %H:%M:%S.%f')
TimeInput(DateTimeBaseInput)        # type="text",带有可选参数format('%H:%M:%S.%f')
CheckboxInput                       # type="checkbox"
Select                              # 下拉菜单,select标签,内涵choices方法
NullBooleanSelect                   # 选项为‘Unknown’、‘Yes’ 和‘No’。
SelectMultiple                      # <select multiple='multiple'>
RadioSelect                         # 类似Select,但是渲染成<li> 标签中的一个单选按钮列表type='radio'
CheckboxSelectMultiple              # 类似SelectMultiple,但是渲染成一个复选框列表type='checkbox'
FileInput                           # type="file"
ClearableFileInput                  # 带有一个额外的复选框,如该字段不是必选的且有初始的数据,可以清除字段的值。
MultipleHiddenInput                 # 一个处理多个隐藏的Widget 的Widget,用于值为一个列表的字段,有choices
SplitDateTimeWidget                 # 有两个可选参数:DateInput 用于日期,TimeInput 用于时间。
SplitHiddenDateTimeWidget           # 类似SplitDateTimeWidget,但是日期和时间都使用HiddenInput
SelectDateWidget                    # 封装三个Select Widget:分别用于年、月、日。
                                     # 注意,这个Widget 与标准的Widget 位于不同的文件中。
                                     # 参数:years,months,empty_label(空值初始化)

     11.3、常用选择插件

# 单radio,值为字符串
user = fields.CharField(
    initial=2,
    widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
)
 
# 单radio,值为字符串
user = fields.ChoiceField(
    choices=((1, '上海'), (2, '北京'),),
    initial=2,
    widget=widgets.RadioSelect
)
 
# 单select,值为字符串
user = fields.CharField(
    initial=2,
    widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)
 
# 单select,值为字符串
user = fields.ChoiceField(
    choices=((1, '上海'), (2, '北京'),),
    initial=2,
    widget=widgets.Select
)
 
# 多选select,值为列表
user = fields.MultipleChoiceField(
    choices=((1,'上海'),(2,'北京'),),
    initial=[1,],
    widget=widgets.SelectMultiple
)
 
 
# 单checkbox
user = fields.CharField(
    widget=widgets.CheckboxInput()
)
 
 
# 多选checkbox,值为列表
user = fields.MultipleChoiceField(
    initial=[2, ],
    choices=((1, '上海'), (2, '北京'),),
    widget=widgets.CheckboxSelectMultiple
)

        拓展: 在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
            方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
 
    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )

    # 因为CharField没有choiecs属性,所以无法user.choiecs
    user2 = fields.CharField(widget=widgets.select(choices=[]))
 
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
        # user2的创建方式是CharField , user的创建方式是choiceField
        self.fields['user2'].widget.choices = models.XXX.objects.all().value_list('id','caption')

            方式二: 使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

# model中的NNewTpye类方法,必须设置__str__(),指定返回的内容。否则authors中存入的是 "NNewType objects"

    11.4、自定义验证规则

        方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )

        方式二:

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
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(Form):
 
 
    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': '标题不能为空',
                                            'min_length': '标题最少为5个字符',
                                            'max_length': '标题最多为20个字符'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': '标题5-20个字符'}))
 
 
    # 使用自定义验证规则
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手机不能为空'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))
 
    email = fields.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

        方式三:

from django import forms
    from django.forms import fields
    from django.forms import widgets
    from django.core.exceptions import ValidationError
    from django.core.validators import RegexValidator
 
    class FInfo(forms.Form):
        username = fields.CharField(max_length=5,
                                    validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
        email = fields.EmailField()
 
        def clean_username(self):
            """
            Form中字段中定义的格式匹配完之后,执行此方法进行验证
            :return:
            """
            value = self.cleaned_data['username']
            if "666" in value:
                raise ValidationError('666已经被玩烂了...', 'invalid')
            return value

        方式四: 同时生成多个标签进行验证

from django.forms import Form
from django.forms import widgets
from django.forms import fields
 
from django.core.validators import RegexValidator
 
 
############## 自定义字段 ##############
class PhoneField(fields.MultiValueField):
    def __init__(self, *args, **kwargs):
        # Define one message for all fields.
        error_messages = {
            'incomplete': 'Enter a country calling code and a phone number.',
        }
        # Or define a different message for each field.
        f = (
            fields.CharField(
                error_messages={'incomplete': 'Enter a country calling code.'},
                validators=[
                    RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
                ],
            ),
            fields.CharField(
                error_messages={'incomplete': 'Enter a phone number.'},
                validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
            ),
            fields.CharField(
                validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
                required=False,
            ),
        )
        super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
                                         **kwargs)
 
    def compress(self, data_list):
        """
        当用户验证都通过后,该值返回给用户
        :param data_list:
        :return:
        """
        return data_list
 
############## 自定义插件 ##############
class SplitPhoneWidget(widgets.MultiWidget):
    def __init__(self):
        ws = (
            widgets.TextInput(),
            widgets.TextInput(),
            widgets.TextInput(),
        )
        super(SplitPhoneWidget, self).__init__(ws)
 
    def decompress(self, value):
        """
        处理初始值,当初始值initial不是列表时,调用该方法
        :param value:
        :return:
        """
        if value:
            return value.split(',')
        return [None, None, None]

    11.5、初始化数据

        在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。

         Form

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
 
class MyForm(Form):
    user = fields.CharField()
 
    city = fields.ChoiceField(
        choices=((1, '上海'), (2, '北京'),),
        widget=widgets.Select
    )

         Views

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        values = {'user': 'root', 'city': 2}
        obj = MyForm(values)
 
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        return redirect('http://www.google.com')
    else:
        return redirect('http://www.google.com')

         HTML

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
 
    <input type="submit"/>
</form>

    11.6、动态操作select数据

# views

from django.shortcuts import render
from app01.forms import UserInfoForm

def index(request):
    obj = UserInfoForm()    # 实例化form对象
    # obj = UserInfoForm({'字段':"默认值"})    # 初始化Form

    # 每个用到usertype的地方,都要写一句这个太麻烦,所以写在构造函数中,一劳永逸。
    # obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name')

    return render(request, 'index.html', {'obj': obj})
# forms.py

from django import forms
from django.forms import fields
from django.forms import widgets

from app01 import models

class UserInfoFrom(forms.Form):
    user = fields.CharField(
        required=False,
        widget=widgets.Textarea(attrs={"class": "c1"})
    )
    pwd = fields.CharField(
        max_length=12,
        widget=widgets.PasswordInput(attrs={"class": "c1"})
    )
    user_type = fields.ChoiceField(
        # choices=[("0", "游客"), ("1", "普通用户"), ("2", "超级用户")],    # 此为默认方法
        choices=models.UserType.objects.values_list("id", "name"),          # 此方法为-数据库读取
        # 上面这个方法存在的问题是,当修改数据库后,只有服务器重启后,页面才刷新
        # 所以使用构造函数的方法 __init__()
        widget=widgets.Select()
    )
    
    def __init__(self, *args, **kwargs):
        super(UserInfoFrom, self).__init__(*args, **kwargs)
        # 每次刷新页面时,会重新读取数据库。
        self.fields['UserType'].choices = models.UserType.objects.values_list("id", "name")
        # 下面使用的是CharField方法时。
        self.fields['UserType'].widgets.choices = models.UserType.objects.values_list("id", "name")

        Form验证----内置钩子

# views.py
def register(request):
    from app01.forms import ResisterForm
    obj = ResisterForm(request.POST)
    if obj.is_valid():
        return render(request, 'register.html', {'obj': obj})
# forms.py
class RegisterForm(forms.Form):
    user = fields.CharField()
    pwd = fields.CharField()

    # form 的第一类钩子,字段的钩子
    def clean_user(self):
        # 此钩子是单纯只处理user字段的验证,其他字段可单独再次验证。
        # 比如,def clean_pwd(self): ... 是单独处理pwd字段。
        c = models.UserInfo.objects.filter(name=self.cleaned_data["user"]).count()
        if not c:
            return self.cleaned_data['user']
        else:
            from django.core.exceptions import ValidationError
            raise ValidationError("用户名已存在", code="xx")

    #form 的第二类钩子,整体的钩子
    def clean(self):
        c = models.UserInfo.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
        if c:
            # 这里返回的是整体的数据,而不是分字段中的 self.cleaned_data['user']。
            return self.cleaned_data
        else:
            from django.core.exceptions import ValidationError
            raise ValidationError("用户名密码错误")

    # form 的第三类钩子
    def _post_clean(self):
        pass

        from错误信息

# views.py
def register(request):
    from app01.forms import ResisterForm
    from django.core.exceptions import NON_FIELD_ERRORS
    obj = ResisterForm(request.POST)
    if obj.is_valid():
        # obj.cleaned_data
        return render(request, 'register.html', {'obj': obj})
    else:
        # obj.errors
        """
        {
            "__all__":[],        # 整体错误信息
            "NON_FIELD_ERRORS":[],        # 整体错误信息的另一个方式
            "user":[{"code":"required","message":"xxxxx"}],
            "pwd":[{"code":"required","message":"xxxxx"}],
        }
        """
        return render(request, 'register.html', {'obj_error': obj.errors})

        form序列化错误信息

# views
import json
from django.shortcuts import HttpResponse
from django.core.exceptions import ValidationError

class JsonCustomEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ValidationError):
            return {'code': o.code, 'messages': o.messages}
        else:
            return json.JSONEncoder.default(self, o)

def login(request):
    if request.method == "GET":
        return render(request, "login.html")
    if request.method == "POST":
        ret = {'status': True, 'error': None, 'data': None}
        obj = LoginForm(request.POST)
        if obj.is_valid:
            print(obj.cleaned_data)
        else:
            ret["status"] = False
            ret['error'] = obj.errors.as_data()
        # json.dumps(str, cls=xx) cls参数是指定每次转码时触发的函数
        result = json.dumps(ret, cls=JsonCustomEncoder)
        return HttpResponse(result)

        form序列化操作总结---- 万变不离其宗

# views
# --------ErrorDict--------
# 自定义 encoder
import json
from django.core.exceptions import ValidationError

class JsonCustomEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ValidationError):
            return {'code': o.code, 'messages': o.messages}
        else:
            return json.JSONEncoder.default(self, o)



# --------QuerySet--------
# 第一种方式:serializers 模块
from django.core import serializers
v = models.tb.objects.all()         # v是一个queryset类型
data = serializers.serialize("json", v)     # 进行序列化~~但格式是django指定的格式

# 第二种方式:
import json
from datetime import date
from datetime import datetime
from django.shortcuts import HttpResponse

class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, datetime):
            # 还记得strftime方法吗?按照指定格式输出字符串
            return field.strftime("%Y-%m-%d %H:%M:%S")
        elif isinstance(field, date):
            return field.strftime("%Y-%m-%d")
        else:
            # 如果是其他类型,则按照默认方式转码
            return json.JSONEncoder.default(self, field)

def index(request):
    v = models.tb.objects.values("id", "name", "ctime")     # 这里的ctime 是时间格式的呦~
    v = list(v)
    v = json.dumps(v, cls=JsonCustomEncoder)
    return HttpResponse(v)

12、ModelForm---(不建议使用,应该使用Form和Model分离的方式)

    1、数据库操作
    2、数据验证
    适合小项目。或者,自定制admin

ModelForm
    a.  class Meta:
            model,                           # 对应Model的
            fields=None,                     # 加载Model中指定的字段,全选则fields="__all__"
            exclude=None,                    # 加载Model中没有指定的字段
            labels=None,                     # 提示信息,类似Model的verbose_name
            help_texts=None,                 # 帮助提示信息
            widgets=None,                    # 自定义插件 django.forms import widgets as Fwidget |widgets={"指定的fields":fwidgets.Textarea}
            error_messages=None,             # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
                                             # 错误信息例子:error_messages = {"name":{"required":"名字不能为空"}}
            field_classes=None               # 自定义字段类 (也可以自定义字段)
            localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
            如:
                数据库中
                    2016-12-27 04:10:57
                setting中的配置
                    TIME_ZONE = 'Asia/Shanghai'
                    USE_TZ = True
                则显示:
                    2016-12-27 12:10:57
    b. 验证执行过程
        is_valid -> full_clean -> 钩子 -> 整体错误
 
    c. 字典字段验证
        def clean_字段名(self):
            # 可以抛出异常
            # from django.core.exceptions import ValidationError
            return "新值"
    d. 用于验证
        model_form_obj = XXOOModelForm()
        model_form_obj.is_valid()
        model_form_obj.errors.as_json()
        model_form_obj.clean()
        model_form_obj.cleaned_data
    e. 用于创建
        model_form_obj = XXOOModelForm(request.POST)
        #### 页面显示,并提交 #####
        # 默认保存多对多
            obj = form.save(commit=True)
        # 不做任何操作,内部定义 save_m2m(用于保存多对多)
            obj = form.save(commit=False)
            obj.save()      # 保存单表信息
            obj.save_m2m()  # 保存关联多对多信息
 
    f. 用于更新和初始化
        obj = model.tb.objects.get(id=1)
        model_form_obj = XXOOModelForm(request.POST,instance=obj)
        ...
 
        PS: 单纯初始化
            model_form_obj = XXOOModelForm(initial={...})

 

14、Ajax操作

    1、原生ajax

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

Asktao
粉丝 27
博文 100
码字总数 116095
作品 0
丰台
程序员
私信 提问
压箱底的收藏,JAVA精华文章大全(一)!

瞧一瞧俺的收藏,N久才收藏全的JAVA精华文章拿出来与大家分享!知名论坛的精华帖子,绝对精华! 精华之王发表了题为《String与基本资料形态之间的转换 》的博客 24分钟前 精华之王发表了题为...

精华之王
2009/04/12
2.4K
6
matlab混合编程向导

matlab混合编程向导(vc,vb,.net...) 一.matlab与vc混编 1.通过mcc将matlab的m文件转化为cpp,c文件或dll供vc调用: 这方面的实现推荐精华区Zosco和ljw总结的方法(x-6-1-4-3-1和2) vc的设置请参...

长平狐
2012/10/08
283
0
matlab混合编程向导(vc,vb,.net...)

一.matlab与vc混编 1.通过mcc将matlab的m文件转化为cpp,c文件或dll供vc调用: 这方面的实现推荐精华区Zosco和ljw总结的方法(x-6-1-4-3-1和2) vc的设置请参看精华区x-6-1-4-3-5,通过这种设置...

云栖希望。
2017/12/04
0
0
Django学习笔记(一)

Django是python web框架中的一种,下面我就介绍一些自己在学习过程中遇到的问题。 官方网站:https://www.djangoproject.com,这个是我们在学习过程中需要重点参考的文档,而且我们需要经常翻...

彩虹的夜晚
2017/10/20
0
0
Linux的page cache使用情况/命中率查看和操控

这里总结几个Linux文件缓存(page cache)使用情况、命中率查看的工具。 perf-tools里面的cachestat 来自于大名鼎鼎的Brendan Gregg的cachestat,已经被加到他的perf-tools http://www.brendan...

21cnbao
2018/05/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

3_数组

3_数组

行者终成事
今天
7
0
经典系统设计面试题解析:如何设计TinyURL(二)

原文链接:https://www.educative.io/courses/grokking-the-system-design-interview/m2ygV4E81AR 编者注:本文以一道经典的系统设计面试题:《如何设计TinyURL》的参考答案和解析为例,帮助...

APEMESH
今天
7
0
使用logstash同步MySQL数据到ES

概述   在生成业务常有将MySQL数据同步到ES的需求,如果需要很高的定制化,往往需要开发同步程序用于处理数据。但没有特殊业务需求,官方提供的logstash就很有优势了。   在使用logstas...

zxiaofan666
今天
10
0
X-MSG-IM-分布式信令跟踪能力

经过一周多的鏖战, X-MSG-IM的分布式信令跟踪能力已基本具备, 特点是: 实时. 只有要RX/TX就会实时产生信令跟踪事件, 先入kafka, 再入influxdb待查. 同时提供实时sub/pub接口. 完备. 可以完整...

dev5
今天
7
0
OpenJDK之CyclicBarrier

OpenJDK8,本人看的是openJDK。以前就看过,只是经常忘记,所以记录下 图1 CyclicBarrier是Doug Lea在JDK1.5中引入的,作用就不详细描述了,主要有如下俩个方法使用: await()方法,如果当前线...

克虏伯
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部