框架----Django框架知识点整理
一、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框架知识点整理的更多相关文章
- WEB框架-Django框架学习-预备知识
今日份整理,终于开始整个阶段学习的后期了,今日开始学习Django的框架,加油,你是最胖的! 1.web基础知识 1.1 web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是 ...
- web 框架的本质及自定义web框架 模板渲染jinja2 mvc 和 mtv框架 Django框架的下载安装 基于Django实现的一个简单示例
Django基础一之web框架的本质 本节目录 一 web框架的本质及自定义web框架 二 模板渲染JinJa2 三 MVC和MTV框架 四 Django的下载安装 五 基于Django实现的一个简单 ...
- day64 django django零碎知识点整理
本文转载自紫金葫芦,哪吒,liwenzhou.cnblog博客地址 简单了解mvc框架和MTV框架, mvc是一种简单的软件架构模式: m----model,模型 v---view,视图 c---co ...
- 框架----Django框架(基础篇)
一.基本配置 一.创建django程序 终端命令:django-admin startproject sitename IDE创建Django程序时,本质上都是自动执行上述命令 其他常用命令: pyt ...
- python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)
12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...
- beego 框架基本使用 && 知识点整理
beego 官网的教程已经整理的非常详细了,但作为一个刚接触的学习者,还是有必要做一下整理,这样在后面使用的时候遇到了不太熟悉的地方,还能反过头来看下自己整理的内容,快速的把知识再捞回来,下面是对官网 ...
- WEB框架-Django框架学习(二)- 模型层
今日份整理为模型层 1.ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库, ...
- 框架----Django框架(进阶篇)
一.Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层 ...
- WEB框架-Django框架学习-关联管理器(RelatedManager)
一.class RelatedManager "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器.它存在于下面两种情况: 1.一对多 ForeignKey关系的“另一边” ...
随机推荐
- sql 命令使用简单记录
半个月前就想记下用过的SQL命令的!!! 主题: 按时间查询: https://blog.csdn.net/hejpyes/article/details/41863349 左关联: se ...
- springmvc传参---LocalDateTime、Date等时间类型转换
此处定义的dateConvert用来转换Date类型,如果是LocalDate.LocalDateTime类型,则将Date类型换成相应的类型即可,注意java8的日期类型需要用Formatter格式 ...
- [C++]boost dijkstra获得两点间的最短路
需求是只需要得到两点间的最短路,不需要求得单源对于全图的最短路,使用boost中的dijsktra_shortest_path,当得到目标点的最短路时直接throw exception. #inclu ...
- Linux环境下Java应用性能分析定位-CPU使用篇
1 CPU热点分析定位背景 CPU资源还是很昂贵的,为了深刻感受到这种昂贵,间下图当前CPU的资源售价: 所以对于程序猿们来说,需要让程序合理高效的使用CPU资源.利用有限的CPU资源来解决完 ...
- Powershell按文件最后修改时间删除多余文件
Powershell按文件最后修改时间删除多余文件 1. 删除目录内多余文件,目录文件个数大于$count后,按最后修改时间倒序排列,删除最旧的文件. Sort-Object -Property La ...
- 四种方式实现波浪效果(CSS效果)
一)第一种方法 (1)HTML结构 <body> <div class="animate wave"> <div class="w1&quo ...
- YQCB冲刺周第二天
YQCB冲刺周第二天 1.实现用户记账的功能 2.实现用户头像的设置 3.实现个人设置的功能 遇到的问题: 记账的分类,数据库存取图片,页面跳转+超链接的使用 团队讨论的照片: ...
- Fiveplus--王者光耀1
**光耀101** 汇总博客: 关文涛: 博客地址:随笔1 随笔2 杨蓝婷: 博客地址:随笔1 随笔2 蔡雅菁: 博客地址:随笔1 随笔2 黄森敏: 博客地址:随笔1 随笔2 林兴源: 博客地址:随笔 ...
- SGU 181 X-Sequence(一题比较水的求模找规律)
E - X-Sequence Time Limit:500MS Memory Limit:4096KB 64bit IO Format:%I64d & %I64u Submit ...
- 周总结<2>
本打算在这周日写周总结的,但由于事情太多,还要组织团日活动,所以没时间写.不过上周主要是一些书本上的学习,但是在周日的时候完成了一款小游戏还是比较有成就感的,但是主要是因为html的考试才去做的. 代 ...