一、cbv

 cbv(class-base-view)    基于类的视图
fbv(func-base-view) 基于函数的视图

a.基本演示

 urlpatterns = [

     url(r'^login.html$', views.Login.as_view()),
]

urls.py

 from django.views import View

 class Login(View):
"""
get 查
post 创建
put 更新
delete 删除
"""
def dispatch(self, request, *args, **kwargs):
print('before')
obj = super(Login,self).dispatch(request,*args,**kwargs)
print("after")
return obj def get(self,request):
return render(request,"login.html") def post(self,request):
print(request.POST) return HttpResponse("Login.post") view.py

views.py

二、分页

a.Django分页

 #浏览器访问
http://127.0.0.1:8000/index.html/?page=9
 urlpatterns = [

     #django分页
url(r'^index', views.index),
]

urls

 #django 分页
from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage
def index(request):
current_page = request.GET.get("page")
user_list = models.User_info.objects.all()
paginator = Paginator(user_list,10) #每页显示10条 """
# count: 数据总个数
# num_pages:总页数
# page_range:总页数的索引范围,如: (1,10),(1,200)
# page: page对象
"""
try:
posts = paginator.page(current_page) #当前页
except PageNotAnInteger as e: #http://127.0.0.1:8000/index.html/?page=qqq 处理这种异常
posts = paginator.page(1)
except EmptyPage as e: #http://127.0.0.1:8000/index.html/?page=-10 捕获这种异常
posts = paginator.page(1) """
# has_next 是否有下一页
# next_page_number 下一页页码
# has_previous 是否有上一页
# previous_page_number 上一页页码
# object_list 分页之后的数据列表
# number 当前页
# paginator paginator对象
""" return render(request,"index.html",{"posts":posts}) views.py

views.py

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户列表</h1>
<ul>
{% for row in posts.object_list %}
<li>{{ row.name }}</li>
{% endfor %}
</ul>
<div>
{% if posts.has_previous %}
<a href="/index.html/?page={{ posts.previous_page_number }}">上一页</a>
{% endif %} {% for num in posts.paginator.page_range %}
<a href="/index.html/?page={{ num }}">{{ num }}</a>
{% endfor %} {% if posts.has_next %}
<a href="/index.html/?page={{ posts.next_page_number }}">下一页</a>
{% endif %}
</div> </body>
</html> index.html

index.html

b.自定义分页

 #浏览器访问
http://127.0.0.1:8000/custom/?page=6
 urlpatterns = [

     #自定义分页
url(r'^custom/', views.custom),
]

urls

 from utils.pager import PageInfo
#自定义分页
def custom(request): #总页数
all_count = models.User_info.objects.all().count() #用户当前想要访问的页码
current_page = request.GET.get("page")
page_info = PageInfo(current_page,all_count,10,"/custom",11) user_list = models.User_info.objects.all()[page_info.start():page_info.end()] return render(request,"custom.html",{"user_list":user_list,"page_info":page_info}) views.py

views.py

 class PageInfo(object):

     def __init__(self,current_page,all_count,per_page,base_url,show_page=11):

         #如果传值错误进入第一页
try:
self.current_page = int(current_page)
except Exception as e:
self.current_page = 1
self.per_page = per_page #每页显示的个数 a,b = divmod(all_count,per_page) #页数 余数
if b:
a = a + 1
self.all_page = a #总页码
self.show_page = show_page
self.base_url = base_url def start(self):
# 1 0: 10
# 2 10:20
# 3 20:30
return (self.current_page-1) * self.per_page def end(self):
return self.current_page * self.per_page def pager(self): page_list = [] half = int((self.show_page-1)/2) if self.all_page < self.show_page:
begin = 1
stop = self.all_page + 1
else:
if self.current_page < half:
begin = 1
stop = self.show_page + 1
else:
if self.current_page + half > self.all_page:
begin = self.all_page - 10 +1
stop = self.all_page + 1
else:
begin = self.current_page - half
stop = self.current_page + half +1 if self.current_page <=1:
prev = "<li><a href='#'>上一页</a></li>"
else:
prev = "<li><a href='%s/?page=%s'>上一页</a></li>"%(self.base_url,self.current_page - 1) page_list.append(prev) for i in range(begin,stop):
if i == self.current_page:
temp = "<li class='active'><a href='/custom/?page=%s'>%s</a></li>"%(i,i)
else:
temp = "<li><a href='%s/?page=%s'>%s</a></li>"%(self.base_url,i,i)
page_list.append(temp) if self.current_page >= self.all_page:
nex = "<li><a href='#'>下一页</a></li>"
else:
nex = "<li><a href='%s/?page=%s'>下一页</a></li>" % (self.base_url,self.current_page + 1) page_list.append(nex) return "".join(page_list) utils/pager.py

utils/pager.py

 from django.db import models

 # Create your models here.

 class User_type(models.Model):
uid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=32) class User_info(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
ut = models.ForeignKey("User_type") models.py

models.py

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css" />
</head>
<body> {% for row in user_list %}
<li>{{ row.name }}</li>
{% endfor %} <nav aria-label="Page navigation">
<ul class="pagination">
{{ page_info.pager |safe }} </ul>
</nav>
</body>
</html> custom.html

custom.html

三、ORM正反向连表操作

 #ORM正反向连表操作
- models
from django.db import models class Foo(models.Model):
"""
第三个表
"""
caption = models.CharField(max_length=16) class UserType(models.Model):
"""
用户类型
"""
title = models.CharField(max_length=32)
fo = models.ForeignKey('Foo') class UserInfo(models.Model):
"""
用户表
"""
name = models.CharField(max_length=16)
age = models.IntegerField()
ut = models.ForeignKey('UserType') - views
----#跨表(正向操作)---UserInfo----含ForeignKey字段 PS: 一个用户只有一个用户类型
# 获取
# QuerySet[obj,obj,obj]
result = models.UserInfo.objects.all()
for obj in result:
print(obj.name,obj.age,obj.ut_id,obj.ut.title,obj.ut.fo.caption) ----#跨表(反向操作)---UserType----不含ForeignKey字段 PS: 一个用户类型下可以有很多用户 obj = models.UserType.objects.all().first()
print('用户类型',obj.id,obj.title)
for row in obj.userinfo_set.all(): #使用的是与之关联的表名小写加_set.all()这个方法取到所有东西
print(row.name,row.age)

四、数据获取多个数据时(注意3种情况的不同之处<跨表查询、跨表取值>)

  # 数据获取多个数据时(注意3种情况的不同之处<跨表查询、跨表取值>)
1. [obj,obj,obj,] # .all()和.filter()拿到的结果是QuerySet对象
models.UserInfo.objects.all()
models.UserInfo.objects.filter(id__gt=1)
result = models.UserInfo.objects.all()
for item in result:
print(item.name,item.ut.title) # 取值方式:item.name,item.ut.title 可以跨表 2. [{id:1,name:fd},{id:1,name:fd},{id:1,name:fd},] # .values()拿到的结果是字典
models.UserInfo.objects.all().values('id','name')
models.UserInfo.objects.filter(id__gt=1).values('id','name')
#无法跨表
result = models.UserInfo.objects.all().values('id','name')
for item in result:
print(item['id'],item['name']) # 取值方式:item['id'],item['name'] #无法跨表
#跨表 使用__(双下划线)
result = models.UserInfo.objects.all().values('id','name',"ut__title") # 这里查询时跨表使用的是ut__title 双下划线
for item in result:
print(item['id'],item['name'],item['ut__title']) # 跨表取值时也用的是双下滑线__ 3. [(1,df),(2,'df')] # .values_list()拿到的结果是元组
models.UserInfo.objects.all().values_list('id','name')
models.UserInfo.objects.filter(id__gt=1).values_list('id','name')
#无法跨表
result = models.UserInfo.objects.all().values_list('id','name')
for item in result:
print(item[0],item[1]) # 取值方式: item[0],item[1] #无法跨表
#跨表 使用__(双下划线)
result = models.UserInfo.objects.all().values_list('id','name',"ut__title") # 这里要跨表使用的是ut__title 双下划线
for item in result:
print(item[0],item[1],item[2]) # 跨表取值时用的是下标

五、CSRF(跨站请求伪造)

CSRF(Cross-site request forgery)跨站请求伪造,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS)
但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。 理解:csrf_token防止从别的网站向自己网站发post请求, 客户来访问网站,网站会向客户发送随机字符串,然后客户带随机字符串发送post请求
只有带随机字符串来,网站才认,一般是post请求才要求带随机字符串,其它网站第一次来不会带随机字符串。

a. django开启csrf

MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware',
]

b.HTML中使用

{% csrf_token %}       #只要写上{% csrf_token %} 会有一个隐藏的input随机字符串,在cookie也有一个随机的字符串,form表单提交数据时,一般会使用
{{ csrf_token }} #生成随机的字符串

c.django中设置防跨站请求伪造功能有分为全局和局部

#局部

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

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

 @csrf_protect
def func(object):
pass #cbv from django.views import View
from django.utils.decorators import method_decorator @method_decorator(csrf_exempt,name="dispatch")
class foo(View)
pass fbv和cbv应用装饰器

fbv和cbv应用装饰器

 #方式一 类上加装饰器:

 def wrapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner @method_decorator(wrapper,name="get")
@method_decorator(wrapper,name="post")
class foo(View): def get(self,request):
pass def post(self,request):
pass #方式二 类上“dispatch”加装饰器: def wrapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner @method_decorator(wrapper,name="dispatch")
class foo(View): def dispatch(self,request,*args,**kwargs):
return xxx def get(self,request):
pass def post(self,request):
pass #方式三 方法上加装饰器: def wrapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner class foo(View): @method_decorator(wrapper)
def get(self,request):
pass def post(self,request):
pass cbv应用其它装饰器

cbv应用其它装饰器

d. Ajax提交数据 携带CSRF

1. 通过获取隐藏的input标签中的字符串,放置在data中发送

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" action="/csrf1.html">
{% csrf_token %}
<input id="user" type="text" name="user"/>
<a onclick="submitForm();">Ajax提交</a>
</form> <script src="/static/jquery-1.12.4.js"></script>
<script>
function submitForm() {
var csrf = $('input[name="csrfmiddlewaretoken"]').val();
var user = $("#user").val();
$.ajax({
url:'/csrf1.html',
type:'POST',
data:{"user":user,"csrfmiddlewaretoken":csrf},
success:function (arg) {
console.log(arg);
} })
}
</script> </body>
</html> csrf1.html

csrf1.html

 urlpatterns = [

     url(r'^csrf1.html', views.csrf1),
]

urls.py

 def csrf1(request):

     if request.method == 'GET':
return render(request,'csrf1.html')
else:
return HttpResponse('ok')

views.py

2. 通过获取返回的cookie中的字符串,放置在请求头中发送

通过在console中 document.cookie可以获取 csrftoken=JPv1gIdrBiAlK2RCrgFs0OKwsncPXvwPfMhEWIVzMdMFymIayiuGu2GkBAu57moL
但需要切割字符串,通过引入jquery.cookie.js对cookie操作,使用$.cookie("csrftoken")
 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" action="/csrf1.html">
{% csrf_token %}
<input id="user" type="text" name="user"/>
<a onclick="submitForm();">Ajax提交</a>
</form> <script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
function submitForm() {
var token = $.cookie("csrftoken");
var user = $("#user").val();
$.ajax({
url:'/csrf1.html',
type:'POST',
headers:{"X-CSRFToken":token},
data:{"user":user},
success:function (arg) {
console.log(arg);
} })
}
</script> </body>
</html> csrf1.html

csrf1.html

六、Django框架最最最最基础的3+5基本使用步骤 。◕‿◕。

 1,创建项目文件夹
在终端Terminal执行命令:
django-admin startproject 项目名 2,配置3个地方
(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_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
) (3) # 'django.middleware.csrf.CsrfViewMiddleware', 注释这一行 3,Django框架5步
在终端Terminal执行命令创建app模块:
python manage.py startapp 模块名 (1)连接数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "studentPro",
'USER':'yangzai',
'PASSWORD':'Oldsyang=5201314@yangzai',
'HOST':'mypy.me',
'PORT':3306,
}
} (2)导入pymysql
在__init__中写入
import pymysql
pymysql.install_as_MySQLdb() (3)创建model
from django.db import models
class UserInfo(models.Model):
id =
name =
password = (4)注册模块
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01' -----这一步
] (5)初始化数据库
python manage.py makemigrations --先执行
  python manage.py migrate --后执行 基本使用步骤

基本使用步骤

七、Django框架里面return的3种返回

return render()        - 返回页面
- return render(request,'index.html',{'std_list':std_list})
3个参数含义:
request:用户的请求信息
'index.html':需要返回的模板html页面
{'std_list':std_list}:存放模板文件里面要被替换的占位符所对应的值 return HttpResponse() - 返回字符串
- return HttpResponse(json.dumps(ret)) return redirect() - 返回url请求
- return redirect('/teachers/') 提示点:redirect,href,action,这3中url请求,都要在地址前加/斜杠
例子:return redirect('/classes.html')
<a href="/edit_class/{{ row.id }}.html">
<form method="POST" action="/edit_class/{{ id }}.html"> return的3中返回

return的3中返回

八、cookie

a. 简单应用

 def login(request):
if request.method=="GET":
return render(request,"login.html")
else:
name = request.POST.get("name")
password = request.POST.get("password")
if name == "alex" and password == "":
obj = redirect("/classes/")
obj.set_cookie("ticket","",max_age=10)
return obj
else:
return redirect("/login/") def classes(request):
sk = request.COOKIES
print(sk)
if not sk:
return redirect("/login/")

b. 过期时间的两种格式

 方式一:
obj.set_cookie("ticket","",max_age=10) 方式二:
import datetime
from datetime import timedelta #时间的加减
ct = datetime.datetime.utcnow() #获取当前日期
v= timedelta(seconds=10) #10秒
value = ct + v obj.set_cookie("ticket","",expires=value)

c. 限制路径

 obj.set_cookie("ticket","",max_age=10,path="/")   #所有路径都可以访问

 obj.set_cookie("ticket","",max_age=10,path="/class")   #只有class访问

d. cookie签名

 #加
obj.set_signed_cookie("ticket","",salt="abc") #解
sk = request.get_signed_cookie("ticket",salt="abc")

九、session

 流程:客户登录网址,验证成功后,服务端生成一个随机字符串和随机字符串对应的键值,然后把随机字符串通过cookie发送给客户端
客户端拿着随机字符串通过cookir再次登陆,服务端拿着随机字符串和保存在本地的数据对应,以确定用户的登录状态
Cookie是什么?
保存在客户端浏览器上的键值对
Session是什么?
保存在服务端的数据(本质是键值对)
{
“aaaaa":{'id':1,'name':'于浩',email='xxxx'}
"bbbbb":{'id':2,'name':'陈涛',email=''}
}
应用:依赖cookie
作用:保持会话(Web网站)
好处:敏感信息不会直接给客户端 梳理:
1. 保存在服务端的数据(本质是键值对)
2. 配置文件中:
- 存储位置
- 超时时间、每次刷新更新时间

session是什么

a. 简单示例

用户访问http://127.0.0.1:8000/login/
urlpatterns = [

    url(r'^index/', views.index),
url(r'^login/', views.login),
]

urls

 def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
u = request.POST.get('user')
p = request.POST.get('pwd')
obj = models.UserAdmin.objects.filter(username=u,password=p).first()
if obj:
# 1. 生成随机字符串
# 2. 通过cookie发送给客户端
# 3. 服务端保存
# {
# 随机字符串1: {'username':'alex','email':x''...}
# }
request.session['username'] = obj.username
return redirect('/index/')
else:
return render(request,'login.html',{'msg':'用户名或密码错误'}) def index(request):
# 1. 获取客户端端cookie中的随机字符串
# 2. 去session中查找有没有随机字符
# 3. 去session对应key的value中查看是否有 username
v = request.session.get('username')
if v:
return HttpResponse('登录成功:%s' %v)
else:
return redirect('/login/') views.py

views.py

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <form action="/login/" method="POST">
<input type="text" name="user">
<input type="text" name="pwd">
<input type="submit" value="提交">{{ msg }}
</form> </body>
</html> login.html

login.html

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <h1>index page</h1> </body>
</html> index.html

index.html

自己的基于session登陆代码:

 def login(request):
if request.method == "GET":
return render(request, "login.html")
else:
input_code = request.POST.get('code')
session_code = request.session.get('code')
username=request.POST.get("user")
password=request.POST.get("pwd")
if input_code.upper() == session_code.upper():
# obj = models.UserInfo.objects.filter(username=username,password=password).first()
obj = models.UserInfo.objects.filter(username=username,password=password).values("nid","avatar",
"nickname",
"blog__title",
"blog__site").first()
print("obj:",obj) # print("obj.nid:",obj.nid)
if obj:
# nid=obj.nid
# request.session["userinfo"]={"id":nid}
request.session["userinfo"]={"id":obj.get("nid"),"avatar":obj.get("avatar"),
"blogname":obj.get("blog__title"),
"nickname":obj.get("nickname"),"site":obj.get("blog__site")}
# print('.................',request.session['userinfo'])
return redirect("/home_page/home_page.html/")
else:
return render(request, 'login.html', {"msg": "用户名或者密码不对"})
else:
return render(request, 'login.html', {"msg": "验证码错误"}) # 退出登陆
def logout(request):
request.session.clear() # 清除session
return redirect('/home_page/home_page.html/')

views

十、URL(路由配置系统)

 URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码<br>对于那个URL调用那段代码

     urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
] 参数说明: 一个正则表达式字符串
一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
可选的要传递给视图函数的默认参数(字典形式)
一个可选的name参数

1. 单一路由对应

 url(r'^index$', views.index)

2. 基于正则的路由

 #  $
url(r'^index/(\d{4})$',views.index) #无命名分组
url(r'^index/(\d{4})/(\d{2})',views.index) #有命名分组
url(r'^index/(?P<year>\d{4})/(?P<month>\d{2})',views.index)
 ############################无命名

 #-----------------() 相当于传参数 

 url(r'^index/(\d{4})',views.index)

     def index(request,arg):
return HttpResponse(arg) #url访问http://127.0.0.1:8000/index/1113 #-----------------() 接受两个参数 url(r'^index/(\d{4})/(\d{2})',views.index) def index(request,arg,arg1):
return HttpResponse("year: %s month: %s"%(arg,arg1)) #url访问http://127.0.0.1:8000/index/2017/06
year: 2017 month: 06 ############################有命名
url(r'^index/(?P<year>\d{4})/(?P<month>\d{2})',views.index) def index(request,year,month):
return HttpResponse("year: %s month: %s"%(year,month)) #url访问http://127.0.0.1:8000/index/2017/06
year: 2017 month: 06 有无命名分组 演示

有无命名分组 演示

3. 为路由映射设置名称

 #应用一:
url(r'^index',views.index,name="arg") {{ url "arg" }} 匹配index
{{ url "arg" i}} #应用二:
reverse反向获取url
 ##############根据url反生成名字
from django.shortcuts import reverse url(r'^index',views.index,name="arg") def index(request):
v = reverse("arg")
print(v)
return HttpResponse() #用户访问http://127.0.0.1:8000/index
/index ##############根据url改变url url(r'^index/(\d+)/',views.index,name="n1") def index(request,xx): v = reverse('n1',args=(1,))
print(v)
return HttpResponse("...") #访问http://127.0.0.1:8000/index/222/
/index/1/ reverse示例 演示

reverse示例 演示

4. 路由分发

 url(r'^app01/',include("app01.urls"))
url(r'^app02/',include("app02.urls")) #没有匹配成功,返回默认页面
url(r'^',include("views.default"))

十一、Model

a. 创建表 

 from django.db import models

 class User_type(models.Model):
uid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=32) class User_info(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
ut = models.ForeignKey("User_type") python3 manage.py makemigrations python3 manage.py migrate ---------------------其它--------------------- class part(models.Model):
cid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=32,null=False) class student(models.Model):
sid = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=32,null=False)
pub_data=models.DateField()
age = models.IntegerField(default=18)
# 新增加的列 如果原先表里有值,写default
ug = models.ForeignKey("part",null=True) #如果新增加外键,加null=True

b. ORM操作

 #增
# models.User_type.objects.create(title="黑金用户") # obj = models.User_type(title="小白用户")
# obj.save() #删
#models.User_type.objects.filter(title="小白用户").delete() # 删除指定条件的数据 #改
#models.User_type.objects.filter(title="黑金用户").update(title="黑卡用户") # 修改指定条件的数据 #查
# models.User_type.objects.get(title="大白用户") # 获取单条数据,不存在则报错(不建议)
# models.User_type.objects.all() # 获取全部
# models.User_type.objects.filter(title="小白用户") # 获取指定条件的数据
# models.User_type.objects.exclude(title="黄金用户") # 排除指定条件的数据 基本增删改查

基本增删改查

 # 获取个数

 models.User_info.objects.filter(age=18).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__gt=1,id__lt=10) # 获取id大于1 且 小于10的值 #in models.User_info.objects.filter(age__in=[19]) # in
models.User_info.objects.exclude(age__in=[19]) # not in # isnull models.User_info.objects.filter(age__isnull=True) # age列为不为空
models.User_info.objects.filter(age__isnull=False) # age列是不是 不为空 # contains # models.Tb1.objects.filter(name__contains="ven")
# models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
# models.Tb1.objects.exclude(name__icontains="ven") # range # models.Tb1.objects.filter(id__range=[1, 5]) # 范围bettwen and #开始 结束 # startswith,istartswith, endswith, iendswith #order_by #models.User_info.objects.all().order_by("id") # asc
#models.User_info.objects.all().order_by("-id") # desc # models.Tb1.objects.filter(name='seven').order_by('id') # asc
# models.Tb1.objects.filter(name='seven').order_by('-id') # desc #group by #后面出现filter代表having from django.db.models import Count
#models.User_info.objects.values("name","age").annotate() #没有起作用
#SELECT "app01_user_info"."name", "app01_user_info"."age" FROM "app01_user_info" #models.User_info.objects.values("age").annotate(xxx=Count("age"))
#SELECT "app01_user_info"."age", COUNT("app01_user_info"."age") AS "xxx" FROM "app01_user_info" GROUP BY "app01_user_info"."age" #models.User_info.objects.values("age").annotate(xxx=Count("age")).filter(xxx__gt=2) #年龄相同次数大于2的查出来
#SELECT "app01_user_info"."age", COUNT("app01_user_info"."age") AS "xxx" FROM "app01_user_info" GROUP BY "app01_user_info"."age" HAVING COUNT("app01_user_info"."age") > 2 #注意两次filter 第一次代表where 第二次代表having #models.User_info.objects.filter(id__gt=2).values("age").annotate(xxx=Count("age")).filter(xxx__gt=2)
#SELECT "app01_user_info"."age", COUNT("app01_user_info"."age") AS "xxx" FROM "app01_user_info" WHERE "app01_user_info"."id" > 2 GROUP BY "app01_user_info"."age" HAVING COUNT("app01_user_info"."age") > 2 常用方法

常用方法

 # F

 # from django.db.models import F
# models.User_info.objects.all().update(age=F("age")+5) # age列加5 # Q # 方式一:
# Q(nid__gt=10)
# Q(nid=8) | Q(nid__gt=10)
# Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') #-------------------------------以下三种查找方式相同效果 # obj = models.User_info.objects.filter(id=307,name="egon") # condition ={
# 'id':307,
# 'name':'egon',
# }
# obj = models.User_info.objects.filter(**condition) #obj = models.User_info.objects.filter(Q(id=307) & Q(name="egon"))
--------------------------------- # 方式二: # 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)) # q3 = Q()
# q3.connector = 'AND'
# q3.children.append(('id', 1))
# q3.children.append(('id', 2))
# q1.add(q3, 'OR') # con = Q()
# con.add(q1, 'AND')
# con.add(q2, 'AND') #(id=1 or id=10 or id=9 or (id=1 and id=2)) and (c1=1 or c1=10 or c1=9) #等于上面 # models.Tb1.objects.filter(con) # Q演示
condition_dict = {
'k1':[1,2,3,4],
'k2':[1,],
'k3':[11,]
} con = Q()
for k,v in condition_dict.items():
q = Q()
q.connector = 'OR'
for i in v:
q.children.append(('id',1))
con.add(q,'AND') models.User_info.objects.filter(con) F Q 演示

F Q 演示

c. 多对多操作

方式一:通过外键创建第三张表

 class Boy(models.Model):
name = models.CharField(max_length=32) class Girl(models.Model):
nick = models.CharField(max_length=32) class Love(models.Model):
b = models.ForeignKey("Boy")
g = models.ForeignKey("Girl") class Meta:
unique_together = [
("b","g"),
]
 #表里插入数据

 objs = [
models.Boy(name='方少伟'),
models.Boy(name='游勤斌'),
models.Boy(name='于浩'),
models.Boy(name='陈涛'),
]
models.Boy.objects.bulk_create(objs,4) result = [
models.Girl(nick='于浩姐姐'),
models.Girl(nick='景甜'),
models.Girl(nick='刘亦非'),
models.Girl(nick='苍老师'),
]
models.Girl.objects.bulk_create(result, 4) models.Love.objects.create(b_id=1,g_id=1)
models.Love.objects.create(b_id=1,g_id=2)
models.Love.objects.create(b_id=1,g_id=3)
models.Love.objects.create(b_id=2,g_id=4) ################### 查找和我有关系的女孩 四种方式 ################ obj = models.Boy.objects.filter(name="方少伟").first()
love_list = obj.love_set.all()
for row in love_list:
print(row.g.nick) love_list = models.Love.objects.filter(b__name="方少伟")
for row in love_list:
print(row.g.nick) #下面两个效果好 love_list = models.Love.objects.filter(b__name="方少伟").values("g__nick")
for item in love_list:
print(item["g__nick"]) love_list = models.Love.objects.filter(b__name="方少伟").select_related("g")
for obj in love_list:
print(obj.g.nick) SQL演示

SQL演示

方式二:通过 ManyToManyField 创建第三张表

 class Boy(models.Model):
name = models.CharField(max_length=32)
m = models.ManyToManyField("Girl") class Girl(models.Model):
nick = models.CharField(max_length=32)
 obj = models.Boy.objects.filter(name="方少伟").first()
# print(obj.id,obj.name) # obj.m.add(2)
# obj.m.add(1,3)
# obj.m.add(*[4,]) # obj.m.remove(2)
# obj.m.remove(1,3)
# obj.m.remove(*[4,]) # obj.m.set([1,4,]) # girl_list = obj.m.all()
# girl_list = obj.m.filter(nick="苍老师") # obj.m.clear() obj = models.Girl.objects.filter(nick="苍老师").first()
v = obj.boy_set.all() SQL 演示

SQL 演示

方式三:通过 外键 和 ManyToManyField 创建

 class Boy(models.Model):
name = models.CharField(max_length=32)
m = models.ManyToManyField("Girl",through="Love",through_fields=("b","g",)) class Girl(models.Model):
nick = models.CharField(max_length=32) class Love(models.Model):
b = models.ForeignKey("Boy")
g = models.ForeignKey("Girl") class Meta:
unique_together = [
("b","g"),
]
 obj = models.Boy.objects.filter(name="方少伟").first()

 #只可以查或清空
obj.m.clear() obj.m.all() SQL 操作

SQL 操作

d. 一对多

 正向:
filter() values,values_list() -> 跨表 fk__xxx
objs = all()
for obj in objs:
obj.fk.
反向:
filter() values,values_list() -> 跨表 表名称__xxx
objs = all()
for obj in objs:
obj.表名称_set.all()

1.连表操作演示

 urlpatterns = [

     url(r'^test/', views.test),

 ]

urls

 class User_type(models.Model):
uid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=32) class User_info(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
ut = models.ForeignKey("User_type") models.py

models.py

 def test(request):
models.User_type.objects.create(title="普通用户")
models.User_type.objects.create(title="白金用户")
models.User_type.objects.create(title="黄金用户") models.User_info.objects.create(name="小鸡",age=18,ut_id=1)
models.User_info.objects.create(name="小狗",age=18,ut_id=2)
models.User_info.objects.create(name="小猫",age=18,ut_id=2)
models.User_info.objects.create(name="小雨",age=18,ut_id=3)
models.User_info.objects.create(name="大雨",age=18,ut_id=1) for i in range(300):
name = "root" + str(i)
models.User_info.objects.create(name=name, age=18, ut_id=1) #正向操作
obj = models.User_info.objects.all().first()
print(obj.name,obj.age,obj.ut.title) #反向操作 obj.表名小写_set.all()
obj = models.User_type.objects.all().first()
for row in obj.user_info_set.all():
print(row.name,row.age) result = models.User_type.objects.all()
for item in result:
print(item.title,item.user_info_set.all())
print(item.user_info_set.filter(name="小雨")) #字典格式
result = models.User_info.objects.all().values("id","name")
for row in result:
print(row) #字典格式查的时候跨表
result = models.User_info.objects.all().values("id","name","ut__title")
for row in result:
print(row["id"],row["name"],row["ut__title"]) # 元组格式
# result = models.User_info.objects.all().values_list("id","name")
# for row in result:
# print(row) return HttpResponse(".....") views.py

views.py

十二、ORM操作

 操作数据行:---------(在views中操作)

models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs
obj = models.Tb1(c1='xx', c2='oo')
obj.save() 删
models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据 改
models.Tb1.objects.filter(name='seven').update(gender='') # 将指定条件的数据更新,均支持 **kwargs
obj = models.Tb1.objects.get(id=1)
obj.c1 = ''
obj.save() # 修改单条数据 查
models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议)
models.Tb1.objects.all() # 获取全部
models.Tb1.objects.filter(name='seven') # 获取指定条件的数据

基本增、删、改、查

 # 获取个数
#
# 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
#
# 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)
# a. 映射
# select
# select_params=None
# select 此处 from 表 # b. 条件
# where=None
# params=None,
# select * from 表 where 此处 # c. 表
# tables
# select * from 表,此处 # c. 排序
# order_by=None
# select * from 表 order by 此处 # 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 #用于构造复杂查询条件 # 应用一:
models.UserInfo.objects.filter(Q(id__gt=1))
models.UserInfo.objects.filter(Q(id=8) | Q(id=2))
models.UserInfo.objects.filter(Q(id=8) & Q(id=2)) # 应用二:
# 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': '','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': '','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):
# 是否有结果 其他操作

其他操作

十三、多表关系以及参数

 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, # 默认创建第三张表时,数据库中表的名称

多表关系以及参数

十四、MVC,MTV

 models(数据库,模型)   views(html模板)    controllers(业务逻辑处理)    --> MVC

 models(数据库,模型)   templates(html模板)  views(业务逻辑处理)          --> MTV

 Django -----基于-----> MTV

十五、事务

示例一:

 try:
from django.db import transaction
with transaction.atomic():
models.UpDown.objects.create(user_id=user_id,article_id=article_id,up=False)
models.Article.objects.filter(nid=article_id).update(down_count=F('down_count')+1)
except Exception as e:
response['status'] = False
response['msg'] = str(e)

示例二:

 #函数里面有数据库操作,加在函数上
from django.db.transaction import atomic @atomic
def cmd(self):
model.....
model.....

十六、随机生成验证码

 # import random
# print(random.random()) #0-1的小数
# print(random.randint(1,3)) #包括1和3
# print("--",random.randrange(1,3)) #不包括1和3 #随机生成四位验证码
import random
checkcode = ''
for i in range(4):
current = random.randrange(0,4)
if current != i:
temp = chr(random.randint(65,90))
else:
temp = random.randint(0,9)
checkcode += str(temp)
print(checkcode)
#KS3G #随机生成8位验证码
import string print(string.ascii_lowercase)
#abcdefghijklmnopqrstuvwxyz
print(string.digits)
# obj = random.sample(string.ascii_lowercase+string.digits,8)
print(obj)
#['i', 'm', 'o', '9', '6', 'p', 'g', '0']
row = "".join(random.sample(string.ascii_lowercase+string.digits,8))
print(row)
#417x6kyt

十七、AEC(高级加密)

 #3.6安装  pip3 install pycryptodome
#mac pip3 install pycrypto

示例:

 ############################### 加密 ##############################

     from Crypto.Cipher import AES
def encrypt(message):
key = b'dfdsdfsasdfdsdfs' #key必须是16的整数倍
cipher = AES.new(key, AES.MODE_CBC, key) #创建对象
----------------------------------------------
#先转成字节,把数据拼够16字节的整数倍
ba_data = bytearray(message,encoding='utf-8') #把数据转成bytearray(byte的数组),bytearray只能追加数字,默认把数字转成字节
v1 = len(ba_data)
v2 = v1 % 16
if v2 == 0:
v3 = 16
else:
v3 = 16 - v2 #v3是追加的长度
for i in range(v3):
ba_data.append(v3) #bytearray只能追加数字,默认把数字转成字节
final_data = ba_data.decode('utf-8')
----------------------------------------------
msg = cipher.encrypt(final_data) #要加密的字符串,必须是16个字节或16个字节的倍数,加密后是byte格式
return msg ############################### 解密 ##############################
def decrypt(msg):
key = b'dfdsdfsasdfdsdfs'
cipher = AES.new(key, AES.MODE_CBC, key)
result = cipher.decrypt(msg) #把加密后的字节解密成不加密的字节
data = result[0:-result[-1]]
return str(data,encoding='utf-8')

十八、前端Format方法

为字符串创建Format方法,用于字符串格式化

 String.prototype.Format=function (arg) {
//console.log(this,arg); //this,当前调用方法的字符串,arg为Format方法传入的参数
//return ''; //return,格式化之后获取的新内容,return啥就替换为啥
var temp = this.replace(/\{(\w+)\}/g,function (k,kk) {
// k相当于{(\w+)},kk相当于(\w+)要替换的东西,arg一般是一个字典
return arg[kk];
});
return temp;
}; #调用
a = {nid}
b = {"nid":""}
a.Format(b)

十九、高级使用----反射

 反射:
getattr(obj,'xxx') 导入模块:
import re
'django.middleware.clickjacking.XFrameOptionsMiddleware'
m = importlib.import_module('django.middleware.clickjacking')
cls = getattr(m,'XFrameOptionsMiddleware')
cls() 面向对象: #示例一: 之后爬虫使用
class Foo:
def __init__(self):
pass @classmethod
def instance(cls):
return cls() def process(self):
pass if hasattr(Foo,'instance'):
obj = Foo.instance()
else:
obj = Foo()
obj.process() #示例二:
class A:
def f1(self):
self.f2() def f2(self):
print('A.f2') class B(A):
def f2(self):
print("B.f2") obj = B()
obj.f1()

二十、request

1 客户端向服务端发送多层字典的值

 obj = {
'data':{
"k1":"v1",
"k2":"v2"
},
'status': True
} #json发送
requests.post("http://www.baidu.com",json=obj) #发送数据内部默认处理(会在内部把字典obj json.dumps序列成字符串,发送给服务端) #body: json.dumps(obj)
#headers= {'content-type':'application/json'} #默认加入 #只有设置如下请求头request.post才能接受,但不能接受多层字典的数据,接受第二层字典只能接受key,不能接受value
#headers= {'content-type':"application/x-www-form-urlencoded"} #接受上面格式发送的数据
if request.method == 'POST':
obj = json.loads(request.body.decode('utf-8'))

2 request.post 和request.body

 #接受
requests.boby
- 请求体原生的值 requests.POST
- 根据特殊的请求头从requests.boby获取数据,不能接受多层字典的数据

3 三者相等

 #方式一:

 requests.post("http://www.baidu.com",json=obj)

 #方式二:

 requests.post(
url="http://www.baidu.com",
headers={'content-type':'application/json'},
data=json.dumps(obj)
) #方式三(): requests.post(
url="http://www.baidu.com",
headers={'content-type':'application/json'},
data=bytes(json.dumps(obj),encoding="utf-8")
)

二十一、hashlib加密(md5)

md5加密

 m = hashlib.md5()
m.update(bytes(new_key,encoding='utf-8')) #里面是字节数据
md5_key = m.hexdigest() #返回值是字符窜类型

二十二、命令行执行Django脚本

 - #效仿manage.py加入的环境变量在脚本的文件加入
- #手动注册django所有的APP  
 import sys,os
-----------------------举例
from audit.backend import user_interactive if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "LuffyAudit.settings")
import django
django.setup() #手动注册django所有的APP
-----------------------举例
obj = user_interactive.UserShell(sys.argv)
obj.start()

二十三、API验证

 API验证:
a. 发令牌: 静态
PS: 隐患 key被别人获取
b. 动态令牌
PS: (问题越严重)用户生成的每个令牌被黑客获取到,都会破解
c. 高级版本
PS: 黑客网速快,会窃取, so要对数据加密
d. 终极版本 特点:
为什么要用API ?
- 数据在传输过程中,保证数据安全
你是如何设计的 ?
- Tornado 中的加密Cookie类似
- 创建动态key md5(key + time)|time (Tornado中也是这么做)
- 限制
- 第一关: 时间
- 第二关: 算法规则
- 第三关: 已访问的记录
PS: 黑客网速快,会窃取, so要对数据加密

1 客户端和服务端都有一个相同的key

 客户端把key发给服务端,服务端拿着自己的key和客户端的key做比较

 ###客户端

 import time
import requests key = "asdfasdfasdfasdf098712sdfs" response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':key})
print(response.text) ###服务端 #print(request.META)
key = request.META.get("HTTP_OPENKEY")
if key != settings.AUTH_KEY:
return HttpResponse("验证失败")

2 key和时间

 #客户端和服务端都有一个相同的key
#客户端把加密key和当前时间发给服务端,服务端收到后把客户端发来的时间和自己的key加密
#然后把加密后的字串和客户端的字串比较 #客户端 import time
import requests
import hashlib ctime = time.time()
key = "asdfasdfasdfasdf098712sdfs"
new_key = "%s|%s" %(key,ctime,) m = hashlib.md5()
m.update(bytes(new_key,encoding='utf-8')) #里面是字节数据
md5_key = m.hexdigest() #返回值是字符串类型 md5_time_key = "%s|%s" %(md5_key,ctime) response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':md5_time_key})
print(response.text) #服务端
client_md5_time_key = request.META.get("HTTP_OPENKEY") client_md5_key,client_ctime = client_md5_time_key.split("|") temp = "%s|%s"%(settings.AUTH_KEY,client_ctime)
m = hashlib.md5()
m.update(bytes(temp, encoding='utf-8'))
server_md5_key = m.hexdigest() if server_md5_key != client_md5_key:
return HttpResponse("验证失败")

3 高级版本

 #客户端和服务端都有一个相同的key
#客户端把加密key和当前时间发给服务端
#服务端验证:
#1)服务端判断服务器当前的时间是否比客户端时间快10s,如果在10s内通过,有效的杜绝了案例二成千上万的key
#2)服务器获取客户端时间和自己key加密然后和 客户端获取到的key比较
#3)删除与现在时间相差10s的数据(之后用memcache,redis)
#3)在字典里判断是否有这个key,如果有不通过,没有加入字典(之后用memcache,redis) #客户端
import time
import requests
import hashlib ctime = time.time()
key = "asdfasdfasdfasdf098712sdfs"
new_key = "%s|%s" %(key,ctime,) m = hashlib.md5()
m.update(bytes(new_key,encoding='utf-8')) #里面是字节数据
md5_key = m.hexdigest() #返回值是字符串类型 md5_time_key = "%s|%s" %(md5_key,ctime) print(md5_time_key)
response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':md5_time_key}) #黑客获取调用
#response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':"f610077a7001c53b5a74868c5544b388|1501514254.455578"})
print(response.text) #服务端
api_key_record ={
"76942d662d98ebe3b920a7b791bf5040|1501510243.92804":1501510243.92804,
} def asset(request): client_md5_time_key = request.META.get("HTTP_OPENKEY") client_md5_key,client_ctime = client_md5_time_key.split("|")
client_ctime = float(client_ctime)
server_ctime = time.time() #第一关 时间关
if server_ctime - client_ctime > 10:
return HttpResponse("第一关 小伙子,别虎我,太长了") #第二关 客户端时间和服务端key加密和 客户端的密钥对比
temp = "%s|%s"%(settings.AUTH_KEY,client_ctime)
m = hashlib.md5()
m.update(bytes(temp, encoding='utf-8'))
server_md5_key = m.hexdigest()
if server_md5_key != client_md5_key:
return HttpResponse("第二关 规则正确") #以后基于memcache,目前先写入内存删除超过10s的值
for k in list(api_key_record.keys()):
v = api_key_record[k]
if server_ctime > v:
del api_key_record[k] #第三关 判断字典里是否有之前访问的key,如果有不通过,没有加入字典
if client_md5_time_key in api_key_record:
return HttpResponse("第三关 已经有人来过了")
else:
api_key_record[client_md5_time_key] = client_ctime + 10

4 终极版本

 注意: key 是从配置文件获取的

 装饰器要返回Httpresponse对象
 __author__ = 'Administrator'
from Crypto.Cipher import AES
from lib.conf.config import settings
def encrypt(message):
"""
数据加密
:param message:
:return:
"""
key = settings.DATA_KEY
cipher = AES.new(key, AES.MODE_CBC, key)
ba_data = bytearray(message,encoding='utf-8')
v1 = len(ba_data)
v2 = v1 % 16
if v2 == 0:
v3 = 16
else:
v3 = 16 - v2
for i in range(v3):
ba_data.append(v3)
final_data = ba_data.decode('utf-8')
msg = cipher.encrypt(final_data) # 要加密的字符串,必须是16个字节或16个字节的倍数
return msg def decrypt(msg):
"""
数据解密
:param message:
:return:
"""
from Crypto.Cipher import AES
key = settings.DATA_KEY
cipher = AES.new(key, AES.MODE_CBC, key)
result = cipher.decrypt(msg) # result = b'\xe8\xa6\x81\xe5\x8a\xa0\xe5\xaf\x86\xe5\x8a\xa0\xe5\xaf\x86\xe5\x8a\xa0sdfsd\t\t\t\t\t\t\t\t\t'
data = result[0:-result[-1]]
return str(data,encoding='utf-8') def auth():
"""
API验证
:return:
"""
import time
import requests
import hashlib ctime = time.time()
key = "asdfasdfasdfasdf098712sdfs"
new_key = "%s|%s" %(key,ctime,) m = hashlib.md5()
m.update(bytes(new_key,encoding='utf-8')) #里面是字节数据
md5_key = m.hexdigest() #返回值是字符窜类型 md5_time_key = "%s|%s" %(md5_key,ctime) return md5_time_key

lib/utils.py

 from Crypto.Cipher import AES
import requests
import json
from lib.utils import encrypt
from lib.utils import auth #对数据加密字典
v1 = encrypt(json.dumps({"k1":"v1"})) #获取的是加密后的字节
print(v1) response = requests.post(
url="http://127.0.0.1:8000/api/asset.html",
headers={'OpenKey':auth(),'content-type':'application/json'},
data=v1
) print(response.text)

客户端调用

 import json
import hashlib
from django.shortcuts import render,HttpResponse
from repository import models
from django.conf import settings
from api.service import PluginManager
import time
import json
from Crypto.Cipher import AES api_key_record ={
"76942d662d98ebe3b920a7b791bf5040|1501510243.92804":1501510243.92804,
} def decrypt(msg):
key = b'dfdsdfsasdfdsdfs'
cipher = AES.new(key, AES.MODE_CBC, key)
result = cipher.decrypt(msg) # 把加密后的字节解密成不加密的字节
data = result[0:-result[-1]]
return str(data, encoding='utf-8') def outer(func):
def wrapper(request):
client_md5_time_key = request.META.get("HTTP_OPENKEY") client_md5_key, client_ctime = client_md5_time_key.split("|")
client_ctime = float(client_ctime)
server_ctime = time.time() # 第一关 时间关
if server_ctime - client_ctime > 30:
return HttpResponse("第一关 小伙子,别虎我,太长了") # 第二关 客户端时间和服务端key加密和 客户端的密钥对比
temp = "%s|%s" % (settings.AUTH_KEY, client_ctime)
m = hashlib.md5()
m.update(bytes(temp, encoding='utf-8'))
server_md5_key = m.hexdigest()
if server_md5_key != client_md5_key:
return HttpResponse("第二关 规则正确") # 以后基于memcache,目前先写入内存删除超过10s的值
for k in list(api_key_record.keys()):
v = api_key_record[k]
if server_ctime > v:
del api_key_record[k] # 第三关 判断字典里是否有之前访问的key,如果有不通过,没有加入字典
if client_md5_time_key in api_key_record:
return HttpResponse("第三关 已经有人来过了")
else:
api_key_record[client_md5_time_key] = client_ctime + 10
obj = func(request)
return obj return wrapper @outer
def asset(request): if request.method == 'GET':
ys = '重要的不能被闲杂人等看的数据'
return HttpResponse(ys) elif request.method == 'POST': server_info = decrypt(request.body)
server_info = json.loads(server_info) # # 新资产信息
# server_info = json.loads(request.body.decode('utf-8'))
hostname = server_info['basic']['data']['hostname']
# 老资产信息
server_obj = models.Server.objects.filter(hostname=hostname).first()
if not server_obj:
return HttpResponse('当前主机名在资产中未录入') PluginManager(server_info,server_obj,hostname).exec_plugin() return HttpResponse("...")

服务端代码

二十四、KindEditor

1 进入官网

2 下载

官网下载:http://kindeditor.net/down.php

3 文件夹说明

 ├── asp                          asp示例
├── asp.net asp.net示例
├── attached 空文件夹,放置关联文件attached
├── examples HTML示例
├── jsp java示例
├── kindeditor-all-min.js 全部JS(压缩)
├── kindeditor-all.js 全部JS(未压缩)
├── kindeditor-min.js 仅KindEditor JS(压缩)
├── kindeditor.js 仅KindEditor JS(未压缩)
├── lang 支持语言
├── license.txt License
├── php PHP示例
├── plugins KindEditor内部使用的插件
└── themes KindEditor主题

4 基本使用

 <textarea name="content" id="content"></textarea>

 <script src="/static/jquery-1.12.4.js"></script>
<script src="/static/plugins/kind-editor/kindeditor-all.js"></script>
<script>
$(function () {
initKindEditor();
}); function initKindEditor() {
var kind = KindEditor.create('#content', {
width: '100%', // 文本框宽度(可以百分比或像素)
height: '300px', // 文本框高度(只能像素)
minWidth: 200, // 最小宽度(数字)
minHeight: 400 // 最小高度(数字)
});
}
</script>

5 详细参数

http://kindeditor.net/docs/option.html

6 上传文件示例

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <div>
<h1>文章内容</h1>
{{ request.POST.content|safe }}
</div> <form method="POST">
<h1>请输入内容:</h1>
{% csrf_token %}
<div style="width: 500px; margin: 0 auto;">
<textarea name="content" id="content"></textarea>
</div>
<input type="submit" value="提交"/>
</form> <script src="/static/jquery-1.12.4.js"></script>
<script src="/static/plugins/kind-editor/kindeditor-all.js"></script>
<script>
$(function () {
initKindEditor();
}); function initKindEditor() {
var a = 'kind';
var kind = KindEditor.create('#content', {
width: '100%', // 文本框宽度(可以百分比或像素)
height: '300px', // 文本框高度(只能像素)
minWidth: 200, // 最小宽度(数字)
minHeight: 400, // 最小高度(数字)
uploadJson: '/kind/upload_img/',
extraFileUploadParams: {
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
fileManagerJson: '/kind/file_manager/',
allowPreviewEmoticons: true,
allowImageUpload: true
});
}
</script>
</body>
</html>

HTML

 import os
import json
import time from django.shortcuts import render
from django.shortcuts import HttpResponse def index(request):
"""
首页
:param request:
:return:
"""
return render(request, 'index.html') def upload_img(request):
"""
文件上传
:param request:
:return:
"""
dic = {
'error': 0,
'url': '/static/imgs/20130809170025.png',
'message': '错误了...'
} return HttpResponse(json.dumps(dic)) def file_manager(request):
"""
文件管理
:param request:
:return:
"""
dic = {}
root_path = '/Users/wupeiqi/PycharmProjects/editors/static/'
static_root_path = '/static/'
request_path = request.GET.get('path')
if request_path:
abs_current_dir_path = os.path.join(root_path, request_path)
move_up_dir_path = os.path.dirname(request_path.rstrip('/'))
dic['moveup_dir_path'] = move_up_dir_path + '/' if move_up_dir_path else move_up_dir_path else:
abs_current_dir_path = root_path
dic['moveup_dir_path'] = '' dic['current_dir_path'] = request_path
dic['current_url'] = os.path.join(static_root_path, request_path) file_list = []
for item in os.listdir(abs_current_dir_path):
abs_item_path = os.path.join(abs_current_dir_path, item)
a, exts = os.path.splitext(item)
is_dir = os.path.isdir(abs_item_path)
if is_dir:
temp = {
'is_dir': True,
'has_file': True,
'filesize': 0,
'dir_path': '',
'is_photo': False,
'filetype': '',
'filename': item,
'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
}
else:
temp = {
'is_dir': False,
'has_file': False,
'filesize': os.stat(abs_item_path).st_size,
'dir_path': '',
'is_photo': True if exts.lower() in ['.jpg', '.png', '.jpeg'] else False,
'filetype': exts.lower().strip('.'),
'filename': item,
'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
} file_list.append(temp)
dic['file_list'] = file_list
return HttpResponse(json.dumps(dic))

views

7 XSS过滤特殊标签

处理依赖

pip3 install beautifulsoup4
 from bs4 import BeautifulSoup

 class XSSFilter(object):
__instance = None def __init__(self):
# XSS白名单
self.valid_tags = {
"font": ['color', 'size', 'face', 'style'],
'b': [],
'div': [],
"span": [],
"table": [
'border', 'cellspacing', 'cellpadding'
],
'th': [
'colspan', 'rowspan'
],
'td': [
'colspan', 'rowspan'
],
"a": ['href', 'target', 'name'],
"img": ['src', 'alt', 'title'],
'p': [
'align'
],
"pre": ['class'],
"hr": ['class'],
'strong': []
} @classmethod
def instance(cls):
if not cls.__instance:
obj = cls()
cls.__instance = obj
return cls.__instance def process(self, content):
soup = BeautifulSoup(content, 'lxml')
# 遍历所有HTML标签
for tag in soup.find_all(recursive=True):
# 判断标签名是否在白名单中
if tag.name not in self.valid_tags:
tag.hidden = True
if tag.name not in ['html', 'body']:
tag.hidden = True
tag.clear()
continue
# 当前标签的所有属性白名单
attr_rules = self.valid_tags[tag.name]
keys = list(tag.attrs.keys())
for key in keys:
if key not in attr_rules:
del tag[key] return soup.renderContents() if __name__ == '__main__':
html = """<p class="title">
<b>The Dormouse's story</b>
</p>
<p class="story">
<div name='root'>
Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>;
and they lived at the bottom of a well.
<script>alert(123)</script>
</div>
</p>
<p class="story">...</p>""" v = XSSFilter.instance().process(html)
print(v)

XSS示例

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
from bs4 import BeautifulSoup class XSSFilter(object):
__instance = None def __init__(self):
# XSS白名单
self.valid_tags = {
"font": ['color', 'size', 'face', 'style'],
'b': [],
'div': [],
"span": [],
"table": [
'border', 'cellspacing', 'cellpadding'
],
'th': [
'colspan', 'rowspan'
],
'td': [
'colspan', 'rowspan'
],
"a": ['href', 'target', 'name'],
"img": ['src', 'alt', 'title'],
'p': [
'align'
],
"pre": ['class'],
"hr": ['class'],
'strong': []
} def __new__(cls, *args, **kwargs):
"""
单例模式
:param cls:
:param args:
:param kwargs:
:return:
"""
if not cls.__instance:
obj = object.__new__(cls, *args, **kwargs)
cls.__instance = obj
return cls.__instance def process(self, content):
soup = BeautifulSoup(content, 'lxml')
# 遍历所有HTML标签
for tag in soup.find_all(recursive=True):
# 判断标签名是否在白名单中
if tag.name not in self.valid_tags:
tag.hidden = True
if tag.name not in ['html', 'body']:
tag.hidden = True
tag.clear()
continue
# 当前标签的所有属性白名单
attr_rules = self.valid_tags[tag.name]
keys = list(tag.attrs.keys())
for key in keys:
if key not in attr_rules:
del tag[key] return soup.renderContents() if __name__ == '__main__':
html = """<p class="title">
<b>The Dormouse's story</b>
</p>
<p class="story">
<div name='root'>
Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>;
and they lived at the bottom of a well.
<script>alert(123)</script>
</div>
</p>
<p class="story">...</p>""" obj = XSSFilter()
v = obj.process(html)
print(v)

基于__new__实现单例模式示例

8 示例图

二十五、Django多级评论

1 原理

 #多级评论原理简单原理,弄完之后发现基础白学了
msg_list = [
{'id':1,'content':'xxx','parent_id':None},
{'id':2,'content':'xxx','parent_id':None},
{'id':3,'content':'xxx','parent_id':None},
{'id':4,'content':'xxx','parent_id':1},
{'id':5,'content':'xxx','parent_id':4},
{'id':6,'content':'xxx','parent_id':2},
{'id':7,'content':'xxx','parent_id':5},
{'id':8,'content':'xxx','parent_id':3},
]
#python里面的apend之类的东西都是引用的原来数据的内从地址,对原数据进行操作的话
#我们引用的数据也会发生一样的变化(字典列表之类的) #骗子的方法
# for i in msg_list:
# i['child']=[]
# for i in range(len(msg_list)-1,-1,-1):
# if msg_list[i]['parent_id']:
# msg_list[msg_list[i]['parent_id'] - 1]['child'].append(msg_list[i])
# new_msg_list = [i for i in msg_list if i['parent_id'] is None]
# print(new_msg_list) #老师讲的方法
# v=[row.setdefault('child',[]) for row in msg_list] #这和地下的第一个for循环的作用是一样的,给每一个元素加一个'child':[]
# print(msg_list)
#如果我们想加快索引(快点找到数据的话)就建一个字典的数据结构
msg_list_dict={} #加快索引,节省时间
for item in msg_list:
item['child']=[]
msg_list_dict[item['id']]=item #字典中key为item['id'],value为item
#把字典数据结构填上数据,能够加快索引,而且我们数据还是占得原来的内从空间
#我们只是引用了数据的内容空间,所以不存在新的数据结构浪费空间一说
result=[]
for item in msg_list:
pid=item['parent_id']
if pid: #如果parent_id不为空,说明它是子级,要把自己加入对应的父级
msg_list_dict[pid]['child'].append(item)
else: #如果为空,说明他是父级,要把它单独领出来用
result.append(item)
#result就是我们最终要的结果,因为这里面全是引用,所有数据的内存地址都没有变
#只不过被多个数据结构引用了而已
print(result)

2 精简版

 def comments(request,nid):
res={'status':True,'data':None,'msg':None}
try:
comment_list = models.Comment.objects.filter(article_id=nid).values()
com_list = list(comment_list) # 所有的评论,列表套字典
com_list_dict = {} # 建立一个方便查找的数据结构字典
for item in com_list: # 循环评论列表,给每一条评论加一个child:[]就是让他装对他回复的内容
item['create_time'] = str(item['create_time'])
item['child'] = []
com_list_dict[item['nid']] = item
result = []
for item in com_list:
rid = item['reply_id']
if rid: # 如果reply_id不为空的话,那么就是说明他是子评论,我们要把他加入对应的评论后面
com_list_dict[rid]['child'].append(item)
else:
result.append(item)
print(result)
# comment_str = comment_tree(result)
# 这是在服务器上递归完之后,然后在传到前端,但是这样会增加服务器压力
#所以这种方式我们直接就不用了
res['data']=result
except Exception as e:
res['status']=False
res['mag']=str(e)
return HttpResponse(json.dumps(res))

views

 <style>
.comment{
margin-left:20px;
}
</style> <body>
<div id="commentArea"> </div>
</body>
<script src="/static/jquery-3.2.1.js"></script>
<script>
//自定义JS中字符串格式化方法
String.prototype.Format=function (arg) {
//console.log(this,arg); //this,当前调用方法的字符串,arg为Format方法传入的参数
//return '666'; //return,格式化之后获取的新内容,return啥就替换为啥
var temp = this.replace(/\{(\w+)\}/g,function (k,kk) {
// k相当于{(\w+)},kk相当于(\w+)要替换的东西,arg一般是一个字典
return arg[kk];
});
return temp;
}; $(function () {
//发送Ajax请求,获取所有评论的信息
//列表
//JS生成结构
var token=$.cookie('csrftoken');
$.ajax({
url:"/comments-{{ article_obj.nid }}.html",
type:"GET",
dataType:"JSON",
success:function (arg) {
if (arg.status){
var comment=commentTree(arg.data);
$('#commentArea').append(comment);
}else{
alert(arg.msg);
}
}
})
}); //多级评论递归函数,js函数里面也有return,自己写js字符串格式化
//pyhton中字符串的方法都是str下的,js中是String.prototype下找的
function commentTree(commentList) {
var comment_str="<div class='comment'>";
$.each(commentList,function (k,row) {
var temp="<div class='content'>{content}</div>".Format({content:row.content});
comment_str += temp;
if (row.child.length>0){
comment_str += commentTree(row.child);
}
});
comment_str += '</div>';
return comment_str
}
</script>

html

二十六、REST framework

1. 什么是REST

  • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
  • REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
  • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
  • 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
  • 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

设计参考:http://www.ruanyifeng.com/blog/2014/05/restful_api.html

2. 目前如何实现 REST API ?

按照规则,根据不同的请求方式做出不同的处理,并且返回内容以及相应状态码

3. 什么是 Django REST framework

Django REST framework是一个基于Django开发的app,用于快速搭建REST API。

安装:

 pip3 install djangorestframework

a. 快速使用

INSTALLED_APPS = [
...
'rest_framework',
]

1.注册APP

 from rest_framework import routers
from . import views router = routers.DefaultRouter()
router.register(r'users', views.UserInfoViewSet) urlpatterns = [
url(r'^', include(router.urls)),
]

2.注册路由

 from rest_framework import viewsets
from . import models
from . import serializers # ########### 1. 基本处理方式 ########### class UserInfoViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = models.UserInfo.objects.all().order_by('-id')
serializer_class = serializers.UserInfoSerializer

3.编写ViewSet,视图函数

 from rest_framework import serializers
from . import models class UserInfoSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.UserInfo
# fields = ('id', 'username', 'pwd','ug') # fields = '__all__'
exclude = ('ug',)
depth = 1 # 0<=depth<=10

4.编写serializers,form验证以及数据库操作

PS:最终访问路径

 [GET]          http://127.0.0.1:8000/api/users/
[POST] http://127.0.0.1:8000/api/users/
[GET] http://127.0.0.1:8000/api/users/7/
[PUT] http://127.0.0.1:8000/api/users/7/
[DELETE] http://127.0.0.1:8000/api/users/7/

b. 基于CBV

 from django.conf.urls import url,include
from django.contrib import admin
from . import views urlpatterns = [
url(r'^users/$', views.UserList.as_view()),
url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
]

1.URL

 from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser
from . import models
from . import serializers class UserList(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all()
serializer = serializers.MySerializer(instance=user_list, many=True)
return Response(serializer.data) def post(self, request, *args, **kwargs):
data = JSONParser().parse(request)
serializer = serializers.MySerializer(data=data)
if serializer.is_valid():
# print(serializer.data)
# print(serializer.errors)
# print(serializer.validated_data)
# 如果有instance,则执行update方法;否则,执行create
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400) class UserDetail(APIView):
def get(self, request, *args, **kwargs):
obj = models.UserInfo.objects.filter(pk=kwargs.get('pk')).first()
serializer = serializers.MySerializer(obj)
return Response(serializer.data) def delete(self, request, *args, **kwargs):
obj = models.UserInfo.objects.filter(pk=kwargs.get('pk')).first()
obj.delete()
return Response(status=204) def put(self, request, *args, **kwargs):
data = JSONParser().parse(request)
obj = models.UserInfo.objects.filter(pk=kwargs.get('pk')).first()
serializer = serializers.MySerializer(obj, data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=400)

2.编写视图函数

 from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from . import models class MySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
username = serializers.CharField(required=False, allow_blank=True, max_length=100)
pwd = serializers.CharField() def validate_username(self, value):
if value == '中国':
raise ValidationError('用户名中存在敏感字符')
return value def validate_pwd(self, value):
print(value)
return value def validate(self, attrs):
print(attrs)
return attrs def create(self, validated_data):
"""
当执行save方法时,自动调用。instance未传值
:param validated_data:
:return:
"""
print(validated_data)
return models.UserInfo.objects.create(**validated_data) def update(self, instance, validated_data):
"""
当执行save方法时,自动调用。instance传值
:param instance:
:param validated_data:
:return:
"""
instance.username = validated_data.get('username', instance.username)
instance.save()
return instance

3.编写serializers

c. 基于CBV

 from django.conf.urls import url,include
from django.contrib import admin
from . import views urlpatterns = [
url(r'^users/$', views.user_list),
url(r'^users/(?P<pk>[0-9]+)/$', views.user_detail),
]

1.URL

 from django.http import JsonResponse,HttpResponse
from rest_framework.response import Response
from rest_framework.parsers import JSONParser
from rest_framework.decorators import api_view
from .serializers import MySerializer
from . import models @api_view(['GET',"POST"])
def user_list(request):
"""
List all code snippets, or create a new snippet.
"""
if request.method == 'GET':
user_list = models.UserInfo.objects.all()
serializer = MySerializer(user_list,many=True)
return Response(serializer.data) elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = MySerializer(data=data)
if serializer.is_valid():
print(serializer.data)
print(serializer.errors)
print(serializer.validated_data)
# 如果有instance,则执行update方法;否则,执行create
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400) @api_view(['GET',"POST","PUT"])
def user_detail(request, pk):
"""
Retrieve, update or delete a code snippet.
""" obj = models.UserInfo.objects.filter(pk=pk).first()
if not obj:
return HttpResponse(status=404) if request.method == 'GET':
serializer = MySerializer(obj)
# return JsonResponse(serializer.data,json_dumps_params={'ensure_ascii':False},content_type='application/json;charset=utf-8')
return Response(serializer.data) elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = MySerializer(obj, data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=400) elif request.method == 'DELETE':
obj.delete()
return Response(status=204)

2.视图函数

 from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from . import models class MySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
username = serializers.CharField(required=False, allow_blank=True, max_length=100)
pwd = serializers.CharField() def validate_username(self, value):
if value == '中国':
raise ValidationError('用户名中存在敏感字符')
return value def validate_pwd(self, value):
print(value)
return value def validate(self, attrs):
print(attrs)
return attrs def create(self, validated_data):
"""
当执行save方法时,自动调用。instance未传值
:param validated_data:
:return:
"""
print(validated_data)
return models.UserInfo.objects.create(**validated_data) def update(self, instance, validated_data):
"""
当执行save方法时,自动调用。instance传值
:param instance:
:param validated_data:
:return:
"""
instance.username = validated_data.get('username', instance.username)
instance.save()
return instance

3.编写serializers

d. 权限控制

 REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'permissi.MyPermission',
]
}

1.settings配置文件

 class MyPermission(object):
"""
A base class from which all permission classes should inherit.
""" def has_permission(self, request, view):
"""
Return `True` if permission is granted, `False` otherwise.
""" return True def has_object_permission(self, request, view, obj):
return True

2.权限控制

 - 全局配置
Highcharts.setOptions({
global: {
useUTC: false
}
}); - 主配置
var chart = new Highcharts.Chart('id1', {
title: {
text: '不同城市的月平均气温',
x: 0
},
subtitle: {
text: '数据来源: WorldClimate.com',
x: 0
},
chart: {
events: {
load: function (e) {
// 图标加载时,执行的函数
}
}
},
credits: {
enable: true,
position: {
align: 'right',
verticalAlign: 'bottom'
},
text: '老男孩',
href: 'http://www.oldboyedu.com'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 1
}, xAxis: {
// categories: ['1.1', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
type: 'datetime',
labels: {
formatter: function () {
return Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.value);
},
rotation: 30
} },
yAxis: {
title: {
text: '数值'
}
},
tooltip: {
valueSuffix: '个',
xDateFormat: "%Y-%m-%d %H:%M:%S",
pointFormatter: function (e) {
var tpl = '<span style="color:' + this.series.color + '">●</span> ' + this.series.name + ': <b>' + this.y + '</b><br/>';
return tpl;
},
valueDecimals: 1,
useHTML: true
},
plotOptions: {
series: {
cursor: 'pointer',
events: {
click: function (event) {
// 点击某个指定点时,执行的事件
console.log(this.name, event.point.x, event.point.y);
}
}
}
},
series: [{
name: '东京',
// data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
data: [
[1501689804077.358, 8.0],
[1501689814177.358, 6.9],
[1501689824277.358, 16.9],
[1501689834377.358, 11.9]
]
},
{
name: '洛杉矶',
// data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
data: [
[1501689804077.358, 18.0],
[1501689814177.358, 16.9],
[1501689824277.358, 26.9],
[1501689834377.358, 9.9]
]
}]
}); // chart.addSeries({name:'北京',data: [216.4, 194.1, 95.6, 54.4, 29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5]});
// 参数:数值;是否重绘; isShift; 是否动画
// chart.series[0].addPoint(18);
// chart.series[0].addPoint([12]);
// chart.series[0].addPoint([v.x, v.y]);
// 参数:是否重绘
// chart.series[0].remove(false);
// 更新饼图
// $('#id1').highcharts().series[0].data[0].update({x: 0, y: 100})

临时放一下

框架----Django框架知识点整理的更多相关文章

  1. WEB框架-Django框架学习-预备知识

    今日份整理,终于开始整个阶段学习的后期了,今日开始学习Django的框架,加油,你是最胖的! 1.web基础知识 1.1 web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是 ...

  2. web 框架的本质及自定义web框架 模板渲染jinja2 mvc 和 mtv框架 Django框架的下载安装 基于Django实现的一个简单示例

    Django基础一之web框架的本质 本节目录 一 web框架的本质及自定义web框架 二 模板渲染JinJa2 三 MVC和MTV框架 四 Django的下载安装 五 基于Django实现的一个简单 ...

  3. day64 django django零碎知识点整理

    本文转载自紫金葫芦,哪吒,liwenzhou.cnblog博客地址 简单了解mvc框架和MTV框架, mvc是一种简单的软件架构模式: m----model,模型 v---view,视图 c---co ...

  4. 框架----Django框架(基础篇)

    一.基本配置 一.创建django程序 终端命令:django-admin startproject sitename IDE创建Django程序时,本质上都是自动执行上述命令 其他常用命令: pyt ...

  5. python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)

    12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...

  6. beego 框架基本使用 && 知识点整理

    beego 官网的教程已经整理的非常详细了,但作为一个刚接触的学习者,还是有必要做一下整理,这样在后面使用的时候遇到了不太熟悉的地方,还能反过头来看下自己整理的内容,快速的把知识再捞回来,下面是对官网 ...

  7. WEB框架-Django框架学习(二)- 模型层

    今日份整理为模型层 1.ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库, ...

  8. 框架----Django框架(进阶篇)

    一.Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层 ...

  9. WEB框架-Django框架学习-关联管理器(RelatedManager)

    一.class RelatedManager "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器.它存在于下面两种情况: 1.一对多 ForeignKey关系的“另一边” ...

随机推荐

  1. Java+Selenium 3.x 实现Web自动化 - Maven打包TestNG,利用jenkins执行测试

    1. Jenkins本地执行测试 or 服务器端执行测试 测试代码计划通过jenkins执行时,通过网上查询各种教程,大多数为本地执行测试,由此可见,本地执行是大多数人的选择. 经过探讨,最终决定采用 ...

  2. Appium + java截图方法

    public static void takeScreenShot(AndroidDriver<WebElement> driver) { File screenShotFile = dr ...

  3. (python)剑指Offer 面试题51:数组中重复的数字

    问题描述 在长度为n的数组中,所有的元素都是0到n-1的范围内. 数组中的某些数字是重复的,但不知道有几个重复的数字,也不知道重复了几次,请找出任意重复的数字. 例如,输入长度为7的数组{2,3,1, ...

  4. C语言—单链表

    单链表操作:读取,插入和删除 #include "stdafx.h" #include <string.h> #include <stdio.h> #inc ...

  5. 微软职位内部推荐-SW Engineer II for Windows System

    微软近期Open的职位: Microsoft's Operating Systems Group delivers the operating system and core user experie ...

  6. Amazon Headlines Update on Activity in US West Coast Ports

    According to news reports, freighter cargo may not be offloaded at U.S. West Coast ports from Februa ...

  7. ubuntu16.04卸载火狐,Amazon

    一.卸载火狐: . dpkg --get-selections |grep firefox .sudo apt-get purge firefox unity-scope-firefoxbookmar ...

  8. lintcode-387-最小差

    387-最小差 给定两个整数数组(第一个是数组 A,第二个是数组 B),在数组 A 中取 A[i],数组 B 中取 B[j],A[i] 和 B[j]两者的差越小越好(|A[i] - B[j]|).返回 ...

  9. WPF浏览器应用程序与JS的互调用(不用WebBrowser)

    首先说些题外话,很久没有写博客了,空间里面的大部分文章还是11年写的.那时候刚毕业就来到这家公司,参与到一个Asp.net MVC的项目开发中,这个项目是一个全新的项目,连项目开发框架都没有,亏得领导 ...

  10. oracle impdp导入时 提示“ORA-39002: 操作无效 ORA-39070: 无法打开日志文件 ”

    第一步:首先使用DBA权限的用户创建directory,我使用system ,可以在服务器本地创建,也可以远程连接sqlplus进行创建,使用的将是服务器上面的路径.要确保创建directory时,操 ...