django_关键点

 

安装

打开命令提示符,然后输入pip3 install django

 

创建优先级

  1.  配置模板的路径:templates
  2. 配置静态目录的路径:static

 

相关命令

 

python manage.py runserver 127.0.0.1:8001  #运行服务器(这个需要命令提示符进入到对应django目录)
django-admin startproject app_name      #创建django项目名(这个需要命令提示符进入到对应django目录C:\Python36\Scripts下运行)
python manage.py startapp app_name      #创建django的APP(这个需要命令提示符进入到对应django目录下运行)
python manage.py makemigrations        #(这个需要命令提示符进入到对应django目录下运行)
python manage.py migrate            #(这个需要命令提示符进入到对应django目录下运行)
python manage.py createsuperuser       # 创建超级管理员(这个需要命令提示符进入到对应django目录下运行)

 

 目录相关信息:

mysite

  -mysite  # 对整个程序进行配置
    -init
    -settings  # 配置文件
    -url     # url对应关系
    -wsgi     # 是一个接口,遵循WSGI规范,上线的时候一般不使用默认的,使用第三方的uwsgi + nginx
  -managy.py   # 管理django程序:

 

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

 

CVB:class  base view

url.py :

urlpatterns = [
    url(r'^home/', views.Home.as_view()),
]

view.py

class Home(View):
    def get(self,request):
        '''执行get方法'''
        return redirect('/cmdb/index/')
    def post(self,request):
        '''执行post方法'''
        return redirect('/cmdb/index/')
CVB

 

from django.views import View
class Home(View):

    def dispatch(self, request, *args, **kwargs):
        '''一般都是先执行该函数,继承了之后,可以对请求之后进行操作'''
        
        print('before')
        result = super(Home,self).dispatch(request, *args, **kwargs)
        print('after')
        return result

    def get(self,request):
        '''执行get方法'''
        return redirect('/cmdb/index/')
    def post(self,request):
        '''执行post方法'''
        return redirect('/cmdb/index/')
CVB2

 

 

FBV:function base view(默认的使用方式)

两者没有哪个好,哪个不好,两者都可以使用

 

URL

from django.conf.urls import url
url(r'^asssssddd/',views.index,name = 'indexx')
url(r'^asssssddd/(\d+)/',views.index,name = 'indexx')
url(r'^user_detail-(?P<nid>\d+)/', views.user_detail), # 正则表达式,对应的函数必须要有参数,这里是一个,所以参数是一个

 

name:访问的url可以指定

对URL路由关系进行命名,以后可以根据此名称生成自己想要的URL
url(r'^asssssddd/',views.index,name = 'indexx')
模板语言:
{% url "indexx" %}

url(r'^asssssddd/(\d+)/',views.index,name = 'indexx')
模板语言(需要增加对应的参数):
{% url "indexx" 3 %}

 

reverse:可以name指定的url转换为绝对URL

url(r'^asssssddd/(\d+)/',views.index,name = 'indexx')
# 反转,根据name的路径转换出对应路径,这里是一个参数,所以args是一个数,
from django.urls import reverse
v = reverse("indexx",args=(80,))
url(r'^asssssddd/(?P<nid>\d+)/(?P<uid>\d+)/',views.index,name = 'indexx')

# 反转,根据name的路径转换出对应路径
from django.urls import reverse
v = reverse("indexx",kwargs={'nid':1,'uid':'99'})

模板语言
{% url "indexx" nid=1 uid=3 %}

 

 include

# 路由会自动切换到app对应目录下的urls.py文件
from django.conf.urls import url,include

urlpatterns = [
    url(r'^cmdb/',include('app01.urls')),
    url(r'^monitor/',include('app02.urls')),
]

# 对应的app里面建立urls.py文件

 

HttpResponse,render,redirect

导入:from django.shortcuts import render,redirect,HttpResponse

HttpResponse:返回字符串到前端

def index(request):
    return HttpResponse('ok')

redirect:跳转到其他路径,重定向,

def index(request):
    return redirect('/crm/king_admin/')

render:自动打开对应文件,读取并将内容返回给前端

def index(request):
    print(king_admin.enabled_admins)
    return render(request, 'king_admin/table_index.html', {'table_list':king_admin.enabled_admins})

 ocals()可以直接将函数中所有的变量全部传给模板

return render(request,'user_audit.html',locals())

 

settings

如果APP需要导入settings文件,可以这样写

from django.conf import settings

 

templates:TEMPLATES 里面的‘DIRS’,加上os.path.join(BASE_DIR,'templates')

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates')],    #设定HTML默认路径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',
            ],
        },
    },
]

 

static:静态文件放置路径

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static'),
]
#备注:django2.0以后必须要使用[]才能获取对应的静态文件路径

 

注册APP:对应app写上,django才能找到对应的models.py,对里面的类进行操作

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'PublicInfo.apps.PublicinfoConfig',    # 将对应app写上,django才能找到对应的models.py,对里面的类进行操作
]

 

数据库:默认为sqllite,若需要修改为mysql,如下修改

# 参考文档 https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'PerfectSet',
        'USER': 'root',
        'PASSWORD': 'Choice123',
        'HOST': '',
        'PORT': '3306',
    },
}

 session

 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过期(默认)这个相当于写cookie的时候不写超时时间
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)True的时候,每次操作,都让session失效时间刷新,例如,无操作20秒后session自动失效

 中间件

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

 

 

request

包含了客户端用户发过来的所有信息(要想知道该对象包含了哪些方法,可以用type(request)获取对应的类,然后进入类查看)

request.environ :封装了所有用户请求信息,字典(根据请求头的信息,可以分辨到是电脑端还是手机端,需要先导入from django.core.handlers.wsgi import WSGIRequest)

request.method:提交方式,访问的时候是get,form表单提交的时候是post(获取的是类似字典的信息)

 

request.POST:获取post获取的信息:eg:reqeust.POST.get('user',None)

 

request.GET:获取get方式的信息

  request.GET.getlist('str')  #获取前端发过来的多个值,如CheckBox等多选的内容

 request.META  # 

request.FILES  #获取前端发送过来的文件所有信息 

obj = request.FILES.get('str')
obj.name        # 文件名
obj.size        # 文件代销
obj.chunks()        # 获取的一段文件信息

 

 # django处理文件一般是用request.FILES,request.FILES.get是获取文件信息,默认返回是文件名称
        obj = request.FILES.get('file')
        print(obj,type(obj))

        import os
        file_path = os.path.join('upload',obj.name)

        f = open(file_path,mode='wb')
        # chunks 相当于一段段获取文件信息
        for i in obj.chunks():
            f.write(i)
        f.close()
上传文件

 

 request.path_info  # 当前url的访问路径

模板语言

循环:

{% for row in user_list %}
{{forloop.counter}}  # 只要是for循环都有一个forloop,这里是计数,从1开始 {
% endfor %}

 

counter        # 从1开始计数
counter0    # 从0开始计数
revcounter    # 倒序,最后为1
revcounter0    # 倒序,最后为0
last        # 是否是最后一个,是的为True
first        # 是否是第一个循环,是未True
parentloop    # 多循环中,获取上一层循环的内容
forloop参数

 

if。。。else

{% if true%}...
{% else %}...
{% endif %}

 

获取后端信息

row.username

 

获取后端的字典

# 获取key
{% for k in user_dict.keys %}
{% endfor %}

# 获取value
{% for v in user_dict.values %}
{% endfor %}

#获取key、values
{% for k,v in user_dict.items %}
{% endfor %}

 

ORM

参考:https://www.cnblogs.com/wupeiqi/articles/6216618.html

创建类
1.根据类自动创建数据库表( APP目录下的models.py):默认为app名称_类名,eg:app01_userinfo
2.根据类对数据库表中的数据进行各种操作

 

 

导入模块:from django.db import models

类需要继承models.Model

from django.db import models

# Create your models here.
class Servers(models.Model):
    '''
    服务器信息,ip地址
    服务器管理账号
    管理密码
    远程端口
    is_used:是否启用
    '''
    ip = models.GenericIPAddressField()
    user = models.CharField(max_length=64)
    pwd = models.CharField(max_length=256)
    port = models.IntegerField(default=3306)
    system = models.ManyToManyField('SystemInfo',null=True,blank=True)
    loca_id = models.ForeignKey('Location',on_delete=models.CASCADE)
    is_used = models.BooleanField(default=True)
eg

 

数据库操作

增:

# (推荐使用第一种)
models.UserInfo.objects.create(username='root',password='123')
或者:
obj= models.UserInfo(username='root',password='123')

  # 这个函数会自动帮忙验证,出错就抛出异常
  obj.full_clean()

  obj.save()

或者:
dic = {'username':'eric','password':'666'}
models.UserInfo.objects.create(**dic')

 

查:

# 获取所有数据,得到django提供的QuerySet类型数据:[obj1对象(id,username.password),obj2,obj3]
result = models.UserInfo.objects.all()
# 也是QuerySet数据,查找特定的列,类似select id,caption from business,内部元素返回的是字典
v2 = models.Business.objects.all().values('id','caption')

# 也是QuerySet数据,查询获取的结果,内部元素返回的是元组
v3 = models.Business.objects.all().values_list('id','caption')

result = models.UserInfo.objects.all().query()  # 可以将执行的sql语句显示
# 条件查询,得到django提供的QuerySet类型数据[] result = models.UserInfo.objects.filter(id=3) result = models.UserInfo.objects.filter(username='root',password='123')

  # 获取单个
  result = models.UserInfo.objects.filter(id=3).first()

  # 获取个数
  result = models.UserInfo.objects.filter(id=3).count()

 

删:

# 删除所有
models.UserInfo.objects.all().delete()
# 删除单个,或者删除所有username叫alex的
models.UserInfo.objects.filter(id=4).delete()
models.UserInfo.objects.filter(username=alex).delete()

 

改(更新):

# 将所有的password改为666
models.UserInfo.objects.all().update(password=666)
# id为3 的那个password改为666
models.UserInfo.objects.filter(id=3).update(password=666)

 


# 批量插入
bulk_create(self,objs,batch_size=None):

优化:

elect_related

# 仅仅对用户表中的数据查询,关联表的数据没有查询
users = models.User.objects.all()
for row in users:
    print(row,user)
    # 查询关联表数据,会再进行数据库操作
    pring(row.ut.name)

# 这样已经对跨表进行操作,进行一次数据库查询,但是获取的是字典
users = models.User.objects.all().values('user','ut__name')

优化:
# 一次操作就将关联的表所有数据都取到,但是数据太多
users = models.User.objects.all().select_related()

再优化:
# 这样就关联了对应外键的数据
users = models.User.objects.all().select_related('ut')

prefetch_related

# 不会做连表查询,会做两次sql请求
users = models.User.objects.filter(id__gt=30).prefetch_related('ut')
# 执行
# select * from users where id > 30
# 获取上一步骤中所有的ut_id = [1,2]
# select * from user_type where id in [1,2]
for row in users:
    print(row,user)
    # 查询关联表数据,不会再进行数据库操作
    pring(row.ut.name)

 

Django admin

写在APP下的admin.py文件里面,必须导入 from django.contrib import admin

models.py里面的类创建字段时候的参数

primary_key = True                # 是否主键
null=True                    # db是否可以为空
default='默认值'                # 默认值
db_coloumn = '列名'                # 列名
unique=True                    # 是否唯一
db_index=True                    # 索引
unique_for_date
unique_for_month
unique_for_year
auto_now=True                    # 创建时,自动生成
auto_now_add=True                # 更新时,自动更新为当前时间
choices                        # django admin中显示下拉框;避免联表查询
blank=True                    # django admin中是否可以为空
verbose_name='中文名'                # django admin中显示字段中文
editable=False                    # django admin中不可以编辑
error_messages={‘required’:'请输入密码'}    # 错误信息显示中文
help_test=‘帮助信息’                # 在旁边一个提示信息
validators                    # django form的自定义验证机制

 

system_type_choices = (
        (0,'windows 2008'),
        (1,'windows 2012')
    )
    system_type = models.SmallIntegerField(choices=system_type_choices,verbose_name='操作系统类型',default=0)
choices使用例子

 外键

to_field 跟表的哪个字段进行关联,不写的情况,默认是主键

on_delete:若删除表的时候,操作的方式

user_id = models.ForeignKey('UserInfo',verbose_name='班级',on_delete=models.CASCADE)

 

创建数据
models.UserInfo.objects.create(
    username = 'alex',
    password = '123',
    email = '123@qq.com',
    user_group = models.UserGroup.objects.filter(id=1).first()
)

# 这里只需要对数据库操作一次,所以建议使用这个
models.UserInfo.objects.create(
    username = 'alex',
    password = '123',
    email = '123@qq.com',
    user_group_id = 1(id=1).first()
)
有外键创建信息

 

通过点跨表获取数据 :'.'

v2 = models.Business.objects.all().values('nid', 'hostname', 'b__id', 'b__caption')
        # print(type(v2))
        for row in v2:
            print(row['nid'], row['hostname'], row['b_id'], row['b__caption'])
            print(row.nid,row.b.caption)

 

字符里面通过双下杠获取数据库数据:'__'  只要是object后面写的,都是用爽下划线跨表

# # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为元组,下标安装下方的写的参数从0排序+1
        v3 = models.Business.objects.all().values_list('nid', 'hostname', 'b_id', 'b__caption')

 

当数据库字段为外键的时候,b对应是对象的情况

 

  h = request.POST.get('hostname')
        i = request.POST.get('ip')
        p = request.POST.get('port')
        b = request.POST.get('b_id')

        models.Host.objects.create(hostname = h,
                                   ip = i,
                                   port = p,
                                   # b = models.Business.objects.get(id=b) b本身是对象,所以这里应该也是对象,但是这样做的话,导致数据库二次操作
                                   b_id = b # 所以,应该是对应id,写成这样
                                   )
b为对象的情况

 

多对多

自定义关系表:多个外键的一对多组成

class Host(models.Model):

    # django会自动生成id,但是也能自己写,需要加上primary_key=True,AutoField整形自增
    nid = models.AutoField(primary_key=True)

    # 主机名,字符串,最大长度32位;db_index=True代表创建索引
    hostname = models.CharField(max_length=32,db_index=True)
    # ip,字符串类型,但是django会自动帮我验证,protocol='both'意思是ipv4以及ipv6都支持
    ip = models.GenericIPAddressField(protocol='both',db_index=True)
    # 端口,数字类型
    port = models.IntegerField()

    # 与表Business关联,to是关联的表,to_field是关联的字段
    b = models.ForeignKey(to="Business",to_field='id',on_delete=models.CASCADE)


class Application(models.Model):
    '''
    应用
    '''
    name = models.CharField(max_length=32)


#
class HostToApp(models.Model):
    '''
    host app关联
    '''
    hobj = models.ForeignKey(to=Host,to_field='nid',on_delete=models.CASCADE)
    aobj = models.ForeignKey(to=Application,to_field='id',on_delete=models.CASCADE)
自定义关系表创建

自动创建关系表(最多三列):ManyToManyField

class Host(models.Model):

    # django会自动生成id,但是也能自己写,需要加上primary_key=True,AutoField整形自增
    nid = models.AutoField(primary_key=True)

    # 主机名,字符串,最大长度32位;db_index=True代表创建索引
    hostname = models.CharField(max_length=32,db_index=True)
    # ip,字符串类型,但是django会自动帮我验证,protocol='both'意思是ipv4以及ipv6都支持
    ip = models.GenericIPAddressField(protocol='both',db_index=True)
    # 端口,数字类型
    port = models.IntegerField()

    # 与表Business关联,to是关联的表,to_field是关联的字段
    b = models.ForeignKey(to="Business",to_field='id',on_delete=models.CASCADE)


class Application(models.Model):
    '''
    应用
    '''
    name = models.CharField(max_length=32)
    # 第三张表自动生成
    r = models.ManyToManyField('Host')
自动创建关系表

建议:以后使用,两种皆可用

使用:

增:

obj = Application.objects.get(id=1)
# 增加
obj.r.add(1) # 增加对应关系1:1
obj.r.add(2) # 增加对应关系1:2
obj.r.add(2,3,4) 
obj.r.add(*[1,2,3,4]) # 增加对应关系

1:1,1:2,1:3,1:4

删:

obj.r.remove(1)         # 删除对应关系1:1
obj.r.remove(2,3,4)     #删除对应关系1:2,1:3,1:4
obj.r.remove(*[1,2,3,4]) # 删除对应关系1:1,1:2,1:3,1:4
obj.r.clear()         # 删除所有1:?的对应关系

改:

obj.r.set([3,5,7])    # 只剩下对应关系1:3,1:5,1:7

查:

# 查(Application.objects后面能加什么,这里就能加什么)
obj.r.all()        # 查询所有

前端获取信息

{% for host in app.r.all %}
        <span >{{ host.hostname }}</span>
{% endfor %}

 

Ajax

本质上,是执行下面代码

obj = XMLHttpRequest()
obj.open()
obj.send()

 

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

  使用 return HttpResponse(json.dumps(字典))

HTML页面,基于jQuery的前提下实现

$.ajax({
    url:'/host',
    type:'POST',
    data:{'k1':'v1','k2':v2}  # 发送的数据
    {#    允许发送列表,不写这个,发送列表的情况会报错#}
    traditional:true,
    {#   写上这句就能让其自动反序列化,所以传递进入函数的就变成了对象#}
     dataType:"JSON",
    success:function(data){
        # 等到服务器返回值后,自动执行,若上面写了dataType:"JSON",data就是对象,否则需要用JSON.parse(data)
    }
{#   若是拿去数据不成功的时候执行的函数#}
     error:function () {

      }
})

 

 EG1:

def test_ajax(request):
    # request.GET.get('pwd',sep='\t')获取pwd的值,并且隔开
    # print(request.method,request.GET.get('user'),request.GET.get('pwd',sep='\t'))

    ret = {'status': True, 'error': None, 'data': None}
    try:

        h = request.POST.get('hostname')
        i = request.POST.get('ip')
        p = request.POST.get('port')
        b = request.POST.get('b_id')
        print(h)
        print(i)
        print(p)
        print(b)
        if h and len(h) > 5:
            models.Host.objects.create(hostname=h,
                                       ip=i,
                                       port=p,
                                       b_id=b
                                       )

        else:
            ret['status'] = False
            ret['error'] = '太短了'


    except Exception as e:
        ret['status'] = False
        ret['error'] = '请求错误'
    return HttpResponse(json.dumps(ret))
views.py

 

$('#ajax_submit').click(function () {
                   $.ajax({
                       url:'/test_ajax',
                       type:'POST',
{#                       data:{'user':'root','pwd':'123'},#}
{#                       获取输入值传递到服务器#}
                         data : {'hostname':$('#hostname').val(),'ip':$('#ip').val(),'port':$('#port').val(),'b_id':$('sel').val()},
{#                       服务器返回信息后,传递到参数data,才执行下面的函数#}
                       success:function (data) {
{#                           反序列化服务器端发过来的json数据#}
                           var obj = JSON.parse(data);
                           {#如果通过验证#}
                           if(obj.status){
                               {#刷新#}
                               location.reload()
                           }else {
                                {#不通过验证的情况下,将错误信息显示到页面#}
                                $('#error_msg').text(obj.error);
                           }
{#                            if(data == 'ok'){#}
{#                           刷新页面#}
{#                                location.reload()#}
{#                            }#}
{#                            else {#}
{#                               alert(data)#}
{#                           alert(data)#}


                       }
                   })
                });
ajax写法

 伪Ajax

iframe变更

ajax
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#    <input type="text" id="url" /><input type="button" value="发送iframe请求" onclick="ifrClick();" />#}
{#    <iframe id="ifm" src="http://wwww.baidu.com" style="width: 500px;height: 500px;">#}
{##}
{#    </iframe>#}
    <form method="post" action="/ajax_json/" target="ifm1">
        {% csrf_token %}
        <iframe name="ifm1"></iframe>
        <input type="text"  name="username"/>
        <input type="text"  name="email"/>
        <input type="submit" value="Form提交"/>

    </form>

    <script type="text/javascript" src="/static/jquery-1.12.4.js"></script>
    <script>
        function ifrClick() {
            var url = $('#url').val();
            $('#ifm').attr('src',url)
        }
    </script>

</body>
</html>
伪Ajax代码

使用的时机:如果发送的是【普通的数据】 ->Jquery,XMLHttpRequest,->iframe

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#    <input type="text" id="url" /><input type="button" value="发送iframe请求" onclick="ifrClick();" />#}
{#    <iframe id="ifm" src="http://wwww.baidu.com" style="width: 500px;height: 500px;">#}
{##}
{#    </iframe>#}
    <form method="post" action="/ajax_json/" target="ifm1">
        {% csrf_token %}
        <iframe name="ifm1" id="ifm1"></iframe>
        <input type="text"  name="username"/>
        <input type="text"  name="email"/>
        <input type="submit" onclick="sumbitForm();" value="Form提交"/>

    </form>

    <script type="text/javascript" src="/static/jquery-1.12.4.js"></script>
    <script>
        function ifrClick() {
            var url = $('#url').val();
            $('#ifm').attr('src',url)
        }
        function sumbitForm() {
            $('#ifm1').load(function () {
                var text = $('#ifm1').contents().find('body').text();
                console.log(text);
                var obj =  JSON.parse(text)
            })
        }
    </script>

</body>
</html>
iframe偷偷发数据,获取后台数据
def ajax_jason(request):
    ret = {'status':400,'data':'dsdsd'}
    import json
    return HttpResponse(json.dumps(ret))
views

基于ajax的文件上传

(参考https://www.cnblogs.com/cheng662540/p/9351284.html

 带iframe的,一般用于文件以及图片上传;

如果要显示图片,只需要将图片的路径返回到前端

可以利用onchange事件,选中文件就自动上传

模板

模板继承(可以多个)

{% extends 'HTML页面名称'%} # 声明继承哪个模板

{% extends 'master.html'%}


上一级模板:
{% block 名字 %} {% endblock %}
eg:

{% block content %} {% endblock %}

如果继承的模板直接写上上面的代码,则表示当前页面使用上一级页面的代码
如果代码块里面写了其他地方,则当前页面使用当前代码

模板导入

{% include 'xx.html'%}

eg:以下为例子
xx.html
<form>
    <input type="text" />
    <input type="submit" />
    {{name}}    # 这个在被导入的过程也是能被渲染的
</form>

index.html
{% include xx.html%}
{% include xx.html%}    # 可以导入多次

自定义 simple_tag

自带的,HTML文件里面写

{{item.event_start|date:"Y-m-d H:i:s"}}    # 将传递过来的日期格式化
{{name|truncatewords:'30'}} # 截取前30个字符

自定义 simple_tag
1.APP下创建目录templatetags(名字只能是这个)
2.目录下创建任意.py文件,如xxoo.py
3.创建template对象,必须为register;代码如下:

from django import template
from django.utils.safestring import mark_safe

# 装饰器,名字不能修改,必须为register
register  = template.Library()

# filter最多传递两个值,这个做法就是类似自带的那种写法
@register.filter
def filter_test(a1,a2):
    return a1 + a2

@register.simple_tag
def houyafan(a1,a2):
    return a1 + a2
xxoo.py

4.settings文件中注册app
5.在HTML顶部写上:{% load xxoo %}(如果有{% extends 'xx.html'%},则写在这个下面)
6.{% 函数名 参数1 参数2 %}

{% houyafan 2 2 %}     # 参数任意,但是不能用于if
{% a1|filter_test:a2 %}  # 这个可以用于if写成


  {% if a1|filter_test:a2 %}

  {% endif %}

 cookie:客户端浏览器上的一个文件,是保存在用户浏览器端的键值对,不适合放敏感信息

 

res = redirect('/index/')
# 设定cookie user111 为u,关闭浏览器失效 res.set_cookie('user111',u) res.set_cookie('key','value') return res

# 获取当前已经登陆的用户信息,因为写了装饰器,所以不需要了
v = request.COOKIES.get('user111')

cookie参数

参数:
        key,              键
        value='',         值
        max_age=None,     超时时间,单位为秒
        expires=None,     超时时间(IE requires expires, so set it if hasn't been already.),到指定日期时间就会失效
        path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
        domain=None,      Cookie生效的域名
        secure=False,     https传输
        httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

eg:

            res = redirect('/index/')
            # 设定cookie user111 为u
            res.set_cookie('user111',u)
            res.set_cookie('key','value')

            import datetime
            # 获取当前时区当前时间
            current_date = datetime.datetime.utcnow()
            # 获取当前时间+多少秒
            current_date = current_date + datetime.timedelta(seconds=10)
            # cookie保持10秒时间
            res.set_cookie('key', 'value',max_age=10)
            res.set_cookie('key', 'value',expires=current_date)

            return res  
View Code

 jQuery有个cookie的插件,可以使用这个,读取cookie信息(jquery.cookie.js)

$.cookie('k1',v)                        # 设置cookie
$.cookie('k1')                          # 获取cookie
$.cookie('k1',v,{'path':'/user_list/'})   # 设置cookie,user_list/路径下的才生效

加密设置、获取cookie

            obj = HttpResponse('ok')
            # 加密设置cookie
            obj.set_signed_cookie('k2','v2',salt='ddddswe')
            #  加密获取cookie
            request.get_signed_cookie('k2',salt='ddddswe')

 基于cookie的装饰器,用于验证用户是否登陆

def auth(func):
    '''
    装饰器,如果发现cookie存储的不是用户名,则需要用户登录
    :param func:
    :return:
    '''
    def inner(request,*args,**kwargs):
        # 获取当前已经登陆的用户信息
        v = request.COOKIES.get('user111')
        if not v:
            return redirect('/login/')
        return func(request,*args,**kwargs)
    return inner

@auth
def index(request):
    # 获取当前已经登陆的用户信息,因为写了装饰器,所以不需要了
    v = request.COOKIES.get('user111')
    # if not v:
    #     return redirect('/login/')

    return render(request,'index.html',{'name':v})
FBV模式

 

def auth(func):
    '''
    装饰器,如果发现cookie存储的不是用户名,则需要用户登录
    :param func:
    :return:
    '''
    def inner(request,*args,**kwargs):
        # 获取当前已经登陆的用户信息
        v = request.COOKIES.get('user111')
        if not v:
            return redirect('/login/')
        return func(request,*args,**kwargs)
    return inner


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

# 在类上面写上这个@method_decorator(auth,name="dispatch")。相当于,在下写了第一个继承的函数,写了这个后,不用写下面的dispatch方法
@method_decorator(auth,name="dispatch")
class Order(views.View):

    # 这里写一个之后,因为所有函数都先执行dispatch的,所以就类里面的所有函数都需要验证
    @method_decorator(auth)
    def dispatch(self, request, *args, **kwargs):
        return super(Order,self).dispatch(request, *args, **kwargs)

    # 写在方法上,是单独对这个方法使用验证
    # @method_decorator(auth)
    def get(self,request):
        # 获取当前已经登陆的用户信息
        v = request.COOKIES.get('user111')

        return render(request, 'index.html', {'name': v})
    def post(self,request):
        # 获取当前已经登陆的用户信息
        v = request.COOKIES.get('user111')
        return render(request, 'index.html', {'name': v})
CVB模式

 

 session:是保存在服务器端的键值对

session的原理:就是服务器端保存一个大字典,将字典的key发送到客户端保存,需要什么的时候,根据这个key就可以查询对应的信息  

session默认情况下是保存在数据库里面的;默认2周有效;session依赖于cookie

'''
利用session,需要做四件事
1.生成随机字符串
2.写到用户浏览器cookie
3.保存到session中
4.在随机字符串对应的字段中设置相关内容
'''
# 这样一句话就完成上面四个操作
request.session['username'] = 'user'
def index(request):
    # 获取当前用户的随机字符串
    # 根据随机字符串获取对应的信息
    # request.session.get('is_login',None)意思是获取is_login信息,没有的时候为None
    if request.session.get('is_login',None):
        return render(request,'index.html',{'username':request.session['username']})
    else:
        return HttpResponse('gun')
    # 用于注销,只删除当前的cookie
    request.session.clear()
    # session保存的时间,单位为秒
    # 人为设置超时时间
    request.session.set_expiry(3)

 

数据库session

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失效策略。
View Code

缓存session

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

文件session

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

缓存+数据库session

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

加密cookiesession

a. 配置 settings.py
     
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

CSRF :可以增强网站的安全性

若要使用这个,全局设置需要再settings文件里面的MIDDLEWARE加上

 'django.middleware.csrf.CsrfViewMiddleware',

 

html里面的form表单需要加上
{% csrf_token %}

    <form action="/login/" method="post">
        <input type="text" name="user" />
        <input type="password" name="pwd" />
        <input type="checkbox" name="rmb" value="1" />3秒钟免登陆
        <input type="submit" value="提交"/>
        <input id="btn1" type="button" value="按钮1"/>
        <input id="btn2" type="button" value="按钮2"/>
        {%  csrf_token %}
    </form>
eg

 

 $(function () {
{#            全局变量,对函数内所有ajax有效#}
            $.ajaxSetup({
                beforeSend:function (xhr,settings) {
{#                    设置请求头#}
                    xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
                }


             });
            
            $('#btn1').click(function () {
{#                var csrftoken = $.cookie('csrftoken');#}
                $.ajax({
                    url:'/login/',
                    type:'POST',
                    data:{'user':'root','pwd':'123'},
{#                    发送post请求的时候,需要加上才放置csrf阻止,由于上面$.ajaxSetup已经配置,所以不需要单独配置#}
{#                    headers:{'X-CSRFtoken':$.cookie('csrftoken')},#}
                    success:function (data) {
                        console.log(1)
                    }
                });
                 $('#btn2').click(function () {
{#                var csrftoken = $.cookie('csrftoken');#}
                $.ajax({
                    url:'/login/',
                    type:'POST',
                    data:{'user':'root','pwd':'123'},
{#                    发送post请求的时候,需要加上才放置csrf阻止#}
{#                    headers:{'X-CSRFtoken':$.cookie('csrftoken')},#}
                    success:function (data) {
                        console.log(2)
                    }
                })
            })
        });
ajax里面加上csrf

函数前面加上@csrf_protect,则表示,这个函数需要做crsf认证

如果前面加上@csrf_exempt,则表示这个函数不需要做csrf认证

from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt
def index(request):
    # 获取当前用户的随机字符串
    # 根据随机字符串获取对应的信息
    # request.session.get('is_login',None)意思是获取is_login信息,没有的时候为None
    if request.session.get('is_login',None):
        return render(request,'index.html',{'username':request.session['username']})
    else:
        return HttpResponse('gun')

 

信号

自带信号

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          # 创建数据库连接时,自动触发
    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)

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

 # 注册多个的情况下,按照顺序执行
    xxoo.connect(callback)
    xxoo.connect(callback1)
    # xxoo指上述导入的内容 ;eg:request_finished.connect(callback)

# 假设是一个根目录下简历一个xxoo.py文件,输入以上代码,若要使用,在目录文件名下的init导入该文件即可:import xxoo
使用:xxoo.py

 

自定义信号(可以做日志)

1.定义信号:

import django.dispatch
# "toppings", "size"是要传递的两个参数
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

2.注册信号

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

3.触发信号

# views.py里面使用
from
路径 import pizza_done pizza_done.send(sender='seven',toppings=123, size=456)

 Form表单验证

1.帮用户验证

2.生成HTML代码

3.保留上次提交的信息内容

导入

from django import forms
from django.forms import fields

建立类

class FM(forms.Form):
  # 将获取到的数据传递到类FM
        obj = FM()

例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/fm/" method="post">
        {% csrf_token %}
{#        <p><input type="text" name="user" />{{ obj.errors.user.0 }}</p>#}
{#        <p><input type="password" name="pwd" />{{ obj.errors.pwd.0 }}</p>#}
{#        <p><input type="text" name="email" />{{ obj.errors.email.0 }}</p>#}
{#        可以生产HTML页面,提交错误的时候,提交的值也会在#}
        <p>{{ obj.user }}{{ obj.errors.user.0 }}</p>
        <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
        <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
        <p>{{ obj.city1 }}{{ obj.errors.city.0 }}</p>
        <p>{{ obj.city2 }}{{ obj.errors.city.0 }}</p>
        <p><input type="submit" value="确定" />
    </form>

</body>
</html>
fm.html
from django import forms
from django.forms import fields
from app01 import models
class FM(forms.Form):
    # 这里的变量与前端form里面的name一致才能获取对应的值
    # user = forms.CharField()
    # 可以自定义对应错误信息
    user = forms.CharField(error_messages={'required':'用户名不能为空。'})

    #  pwd = forms.CharField()
    pwd = forms.CharField(
        max_length=12,
        min_length=6,
        error_messages={'required':'密码不能为空。','min_length':'密码长度不能少于6','max_length':'密码长度不能大于12'}
    )
    # 单选下拉
    city1 = fields.ChoiceField(
        choices=[(0,'上海'),(1,'广州'),(2,'东莞')]
    )
    # 多选下拉
    city2 = fields.MultipleChoiceField(
        choices=[(0, '上海'), (1, '广州'), (2, '东莞')]
    )

    # email = forms.EmailField()
    email = forms.EmailField(error_messages={'required':'邮箱不能为空。','invalid':'邮箱格式错误'})

def fm(request):
    if request.method == 'GET':

        # 从数据库中获取到数据
        dic = {
            'user':'root',
            'pwd':'123123',
            'email':'sada@111',
            'city1':1,
            'city2':[1,2]
        }

        # obj = FM()
        # 将获取到的数据传递到类FM
        obj = FM(initial=dic)
        return render(request,'fm.html',{'obj':obj})
    elif request.method == 'POST':
        # 获取用户所有数据
        # 每条数据请求的验证
        # 成功后,获取所有的正确的信息
        # 如果失败,显示错误信息
        # 这次请求是post里面的数据,所以传入request.POST
        obj = FM(request.POST)
        # 去验证
        r1= obj.is_valid()
        print(r1)
        if r1:
            # cleaned_data 是返回正确的信息,是个字典
            print(obj.cleaned_data)
            # 这样就能创建对应的数据
            models.User.objects.create(**obj.cleaned_data)
        else:
            # obj.errors是字典,是错误的信息
            print(obj.errors)
            print(obj.errors.as_json())
            print(obj.errors['user'])
            print(obj.errors['user'][0])

            return render(request,'fm.html',{'obj':obj})

        return redirect('/fm/')
views.py

HTML页面能够生成对应的标签(自定制性差):

{{obj.as_p}} # 自动生成P标签,然后里面有对应的HTML代码 {{obj.as_ul}} # 自动生成ul标签,然后里面有对应的HTML代码 <table> {{obj.as_table}} # 自动生成P标签,然后里面有对应的HTML代码 </table>

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类型
内置字段

 自定义验证规则

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]
方法四:同时生成多个标签验证

读取数据库信息,初始化数据:

 # 从数据库中获取到数据
        dic = {
            'user':'root',
            'pwd':'123123',
            'email':'sada@111',
            'city1':1,
            'city2':[1,2]
        }

        # obj = FM()
        # 将获取到的数据传递到类FM
        obj = FM(initial=dic)

 

model

参考:https://www.cnblogs.com/wupeiqi/articles/6216618.html

 

自定义认证:

参考:https://docs.djangoproject.com/zh-hans/2.1/topics/auth/customizing/

# 以下为自定义认证使用
class UserProfileManager(BaseUserManager):
    def create_user(self, email, name, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')
        # 相当于创建一条用户记录
        user = self.model(
            email=self.normalize_email(email),
            name=name,
        )
        # 设置密码
        user.set_password(password)
        # 先存放到一个临时地方,再放到数据库
        user.save(using=self._db)
        return user

    def create_superuser(self, email,name, password):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            name=name,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class UserProfile(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    name = models.CharField(max_length=64)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    bind_hosts = models.ManyToManyField('BindHost',blank=True)
    host_groups = models.ManyToManyField('HostGroup',blank=True)

    is_staff = models.BooleanField(
        ('staff status'),
        default=False,
        help_text=('Designate 帮助信息')
    )

    objects = UserProfileManager()

    # 用户名字段是上面的email字段
    USERNAME_FIELD = 'email'
    # 必要的字段
    # REQUIRED_FIELDS = ['date_of_birth']
    REQUIRED_FIELDS = ['name']

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    # @property
    # def is_staff(self):
    #     "Is the user a member of staff?"
    #     # Simplest possible answer: All admins are staff
    #     return self.is_admin
自定义认证需要写上的

settings文件需要配置:

# 使用自定义认证的时候需要设定这个,app.class
AUTH_USER_MODEL = 'web.UserProfile'

 

用户认证

# 登陆验证导入
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate,login,logout
def acc_login(request):
    '''登陆'''
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = authenticate(username=username,password=password)
        if user:
            login(request,user)
            return redirect('/')
        else:
            error_msg = '错误的账号密码!'
            return render(request,'login.html',{'error_msg':error_msg})


    return render(request,'login.html')
登陆
def acc_logout(request):
    '''注销'''
    logout(request)
    return redirect('/login/')
注销

需要认证后才能访问的页面

# 使用@login_required后,settings文件需要修改配置LOGIN_URL = '/login/'
@login_required
def dashboard(request):
    return render(request,'index.html')

 ModelForm

参考:https://www.cnblogs.com/wupeiqi/articles/6229414.html

form可以提供验证、错误信息、正确信息
is_valid-->每一个字段进行正则(字段内置正则)+clean_字段 -->clean(__all__) -->-post_clean

Form验证:
UserInfoForm --> Form -> BaseForm(is_va...)

ModelForm验证
UserInfoModelForm -> ModelForm -> BaseModelForm -> BaseForm

 

ModelForm
    a.  class Meta:
            model,                           # 对应Model的
            fields=None,                     # 字段
            exclude=None,                    # 排除字段
            labels=None,                     # 提示信息
            help_texts=None,                 # 帮助提示信息
            widgets=None,                    # 自定义插件
            error_messages=None,             # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
            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={...})
ModelForm组件

例子:(day24)

from django.db import models


# Create your models here.

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

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

class UserInfo(models.Model):
    username = models.CharField(max_length=32,verbose_name='用户')
    email = models.EmailField(verbose_name='邮箱')
    user_type = models.ForeignKey(to='UserType',to_field='id',on_delete=models.CASCADE,verbose_name='用户类型')
    u2g = models.ManyToManyField(UserGroup)
models
from django.shortcuts import render
from app01 import models
from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):
    is_rmb = Ffields.CharField( #建立额外不保存数据库的字段
        widget=Fwidgets.CheckboxInput(),
        label='是否保存用户信息'
    )
    class Meta:
        model = models.UserInfo
        fields = '__all__'  #显示所有
        # fields = ['username','email']   #显示部分
        # exclude = ['username']      #排除这个外的显示
        labels = {      # 显示名称,比models里面的优先级高
            'username':'用户',

        }
        help_texts = {
            'username':'后面显示的帮助信息'
        }
        widgets = { # 自定义插件,需要使用form里面的widgets
            'username':Fwidgets.Textarea(attrs={'class':'c1'})
        }
        error_messages ={
            'email':{
                'required':'邮箱不能为空',
                'invalid':'邮箱格式不正确',
            }
        }
        # field_classes = {   # 将验证方式从email改为URL
        #     'email':Ffields.URLField
        # }

# Create your views here.

def index(request):
    if request.method == 'GET':
        obj = UserInfoModelForm()
        return render(request, 'index.html', {'obj': obj})
    elif request.method == 'POST':
        obj = UserInfoModelForm(request.POST)
        print(obj.is_valid())
        print(obj.cleaned_data)
        print(obj.errors)
        if obj.is_valid():
            # 保存到数据库,这里一句save相当于下面三句
            # obj.save()
            instance = obj.sava(False)
            instance.save()
            obj.save_m2m()

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

    # render(request,'index.html')

def user_list(request):
    # 跨表操作不能操邹ManyToMany类型,只能是ForeignerKey
    li = models.UserInfo.objects.all().select_related('user_type')
    return render(request,'user_list.html',{'li':li})


def user_edit(request,nid):

    if request.method == 'GET':
        obj = models.UserInfo.objects.filter(id=nid).first()
        # instance=obj将初始值传入
        mf = UserInfoModelForm(instance=obj)
        return render(request,'user_edit.html',{'mf':mf})

    elif request.method == 'POST':
        obj = models.UserInfo.objects.filter(id=nid).first()
        # 传入instance=obj,才能确定是修改这个数据,而不是增加
        mf = UserInfoModelForm(request.POST,instance=obj)
        if mf.is_valid():
            mf.save()
        else:
            print(mf.errors)
        return render(request, 'user_edit.html', {'mf': mf})
views

 

 

 

编辑插件:CKEditor,UEEditor,TinyEditor,KindEditor

集合文件上传、多文件上传、文件空间管理
XSS攻击(过滤的函数或类)

 

logging:

参考:https://www.cnblogs.com/wupeiqi/articles/5501365.html

单文件日志:

import logging
  
  
logging.basicConfig(filename='log.log',
                    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',
                    level=10)
  
logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
logging.log(10,'log')
日志等级
CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0

注:只有【当前写等级】大于【日志等级】时,日志文件才被记录。

 

多文件日志:

# 定义文件
file_1_1 = logging.FileHandler('l1_1.log', 'a', encoding='utf-8')
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
file_1_1.setFormatter(fmt)

file_1_2 = logging.FileHandler('l1_2.log', 'a', encoding='utf-8')
fmt = logging.Formatter()
file_1_2.setFormatter(fmt)

# 定义日志
logger1 = logging.Logger('s1', level=logging.ERROR)
logger1.addHandler(file_1_1)
logger1.addHandler(file_1_2)


# 写日志
logger1.critical('1111')

日志一
日志1
# 定义文件
file_2_1 = logging.FileHandler('l2_1.log', 'a')
fmt = logging.Formatter()
file_2_1.setFormatter(fmt)

# 定义日志
logger2 = logging.Logger('s2', level=logging.INFO)
logger2.addHandler(file_2_1)
日志2

 

注意:

  • url上面,写的访问路径没有/   则form表单上的action写的url也不需要有/;

如果有/,则action也需要有/

url(r'^login/',views.login,

 <form action='/login/'>

 

  • 前端上传文件的时候,需要再form表单里加上  enctype="multipart/form-data

<form method="post" action="/index/" enctype="multipart/form-data">

    </form>

 

  • 修改models.py里面的数据库表结构之后(如果需要使用session,也要执行这两个命令),需要执行命令python manage.py makemigrations;python manage.py migrate

  • django不会自动创建数据库,所以需要先建立数据库

  • django使用mysql,必须要在project同名目录下的init.py文件加上pymysql

import pymysql
pymysql.install_as_MySQLdb()
  • 更新时候能触发auto_now = True更新时间的操作

更新时候能触发auto_now = True更新时间的操作
obj = UserGroup.objects.filter(id=1).first()
obj.caption = 'CEO'
obj.save()
  •  避免XSSl攻击,后端生成的HTML代码,需要加上

# 若想要将对应代码变成想要的效果,可以在HTML页面输出的后端信息,加上|safe
{{page_str|safe}}
# 后端的话,需要导入
from django.utils.safestring import mark_safe
page_str = mark_safe(page_str)

 

posted @ 2018-09-12 20:40  雨之愿风  阅读(232)  评论(0编辑  收藏  举报