目录
常用命令
get和post请求
自定404和500错误
session 设置过时时间
request的几个方法
引入django的设置中的变量
简单请求与复杂请求
利用dajngo自带的ContentType
感觉没啥鸡儿用的django管理器
添加管理器
自定义管理器
Queryset
Queryset缓存机制
Queryset求值情况(惰性查询)
F和Q
F:
Q : Q函数队关键字进行封装, 从而更好地应用多个查询&, | , ~
三个神奇的内置方法
关于update()
admin 注册
布尔字段
多对多添加删除
静态字段(只有choice)
1)重写__init__
2)自动更新(ModelChoiceField)
mark_safe
ajax
is_ajax
ajax的data只能时字符串或数字, 但有数组时
当有字典时
ajax发post
1)加csrf_token
2) 别人写的setupajax.js
跨域
ajax跨域
一 jsonp
二 cors跨域
form表单字段
下拉框
单选框
复选框
判断forn或modelform渲染的字段是不是一对多或多对多
form组件的limit_chocie_to={}
model一些属性
model的get_字段_display()
mode的Meta:
getlist(获取多个值)
CBV
csrf_exempt装饰器
csrf_protect装饰器
url分组匹配
1)url
2) 分组命名匹配
url 分流
url的分发匹配
一级分发
二级分发
多条url访问一个函数(xx/app的名字/表的名字)
模仿admin的url, 实现批量生成app的表的增删改查url
url 反向解析
1) url
2) 模板
3)后台
当url有参数时
url反向解析的命名空间
在python脚本中加载dango项目
Django的一些常用方法
1)get() 和 filter()
2) exclude() 排除
3) values()
4)values_list()
5)order_by()
6)reverse() 只能将排过序的的逆序
7) distinct()
8)first(),last()
9) exists() Queryset有数据返回True, 没数据返回False
10) count() 计数
11)双下划线
12)only和defer
13) bulk_create() 批量插入数据
14)extra() 执行额外的数据库查询
17) 总结
返回Queryset的
返回集体对象的
返回布尔值
返回具体数字
外键查找
正向(从有外键的一方)
反向
手动创建第三张表
分组和聚合 外加 extra() 额外执行查询
聚合
分组
分组的跨表:(在我看来就是玄学)
coikie
session
一个js小demo(通过iput失去焦点向后端发送ajax请求, 可以实时看看有没有重名之类的)
中间件
上传文件到服务器指定位置
Django的密码(把明文密码换成密文)
python manage.py startapp app_name
python manage.py runserver
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py flush 清空数据库
python manage.py changepassword username 修改用户名的密码
python manage.py dumpdata appname > appname.json 导出数据
python manage.py loaddata appname.json 导入数据
python manage.py shell 进入终端
python manage.py dbshell 进入数据库,然后就可以输入sql
get请求类似于 “GET url ?a=1&b=2 http/1.1\r\user_agent:Google\r\ncontentType:urlencode\r\n\r\n'”
post请求类似于 "POST url http/1.1\r\user_agent:Google\r\nconteneType:urlencode\r\n\r\na=1&b=2"
request.body a=1&b=2 (如果是get请求, body没数据)
request.POST 是contentType=urlencode 才有返回值 返回 {’a‘:1, 'b'"2}
1. 首先在settings中设置
DEBUG = False
ALLOWED_HOSTS = ["*"]
2. 在url中
handler500 = views.page_not_found
handler404 = views.page_not_found
网上很多教程说要引入下面的,但实际操作引入pycahrm警告, 不引入正常, 上面404和500 都设置成了一个函数
from django.conf.urls import handler404, handler500
3. views中
from django.shortcuts import render_to_response
def page_not_found(request):
return render_to_response('404.html')
1 .request.session.set_expiry(value)
2. settings中
url = 127.0.0.1:8000/index.html/?p=11&c=6
print(request.GET) < Queryset:{'p':['11'], 'c':['6']} >
print(request.path_info) /index.html/
print(request.path) /index.html/
print(request.get_full_path()) /index.html?p=11&c=6/
a = requet.GET
print(a.urlencode) p=1&c=6
print(request.get_host) 127.0.0.1:8000
from django.conf import settings
if limit != settings.INVITATION_CODE:
raise ValidationError("邀请码不对,请找管理员核对")
概述简单请求发啥请求方式就是啥请求,复杂请求发之前会先发options请求,进行预检,预检不通过,则发的复杂请求也不会通过
简单请求:
1)请求方式为HEAD, GET, POST
2) 请求头信息为:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
同时满足两个条件时, 是简单请求, 否则为复杂请求。
复杂请求:
先发options进行预检, 预检不通过,本身想发的请求也不通过。
对于复杂的请求:
可以写个中间件把复杂请求变成简单请求
from django.utils.deprecation import MiddlewareMixin
class CORSMiddleware(MiddlewareMixin):
def process_response(self, request, response):
# response['Access-Control-Allow-Orign'] = "*"
# 允许全部域名获取数据
# response["Access-control-Allow-Headers"] = "Content-Type"
# 允许携带的xx请求头
# response["Access-Control-Allow-Methods"] = "xx"
# 允许的请求方式, 如写 PUT
response['Access-Control-Allow-Orign'] = "*"
if request.method == 'OPTIONS':
response["Access-control-Allow-Headers"] = "Content-Type"
return response
引自https://www.jianshu.com/p/f2285d77cddd
实现多表关联
models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class Appliance(models.Model):
"""
家用电器表
id name
1 冰箱
2 电视
3 洗衣机
"""
name = models.CharField(max_length=64)
coupons = GenericRelation(to="Coupon")
# 反向查找
def __str__(self):
return self.name
class Food(models.Model):
"""
食物表
id name
1 面包
2 牛奶
"""
name = models.CharField(max_length=32)
def __str__(self):
return self.name
class Fruit(models.Model):
"""
水果表
id name
1 苹果
2 香蕉
"""
name = models.CharField(max_length=32)
def __str__(self):
return self.name
class Coupon(models.Model):
"""
优惠券表
id name appliance_id food_id fruit_id
1 通用优惠券 null null null
2 冰箱折扣券 1 null null
3 电视折扣券 2 null null
4 苹果满减卷 null null 1
我每增加一张表就要多增加一个字段
"""
name = models.CharField(max_length=32)
# 第一步
content_type = models.ForeignKey(to=ContentType)
# 第二步
object_id = models.PositiveIntegerField()
# 第三步
content_object = GenericForeignKey('content_type', 'object_id')
def __str__(self):
return self.name
view.py
from django.shortcuts import render, HttpResponse
from django import views
from app01 import models
class Text(views.View):
def get(self, request):
# 通过ContentType获得表名
content = models.ContentType.objects.filter(app_label="app01", model="appliance").first()
# 获得表model对象 相当于models.Applicance
model_class = content.model_class()
obj_list = model_class.objects.all()
# 创建:给电器的冰箱添加优惠券
# 第一步,将想要添加优惠券的对象取出
obj = models.Appliance.objects.filter(pk=2).first()
# 第二步,创建优惠券,传入两个参数name="冰箱优惠券", content_object=obj
models.Coupon.objects.create(name="冰箱优惠券", content_object=obj)
# 正向查询:查询优惠券id=1绑定了哪个商品
Coupon_obj = models.Coupon.objects.filter(pk=1).first()
goods_obj = Coupon_obj.content_object
print(goods_obj)
# 反向查询之定义了coupons = GenericRelation(to="Coupon")
appliance_obj = models.Appliance.objects.filter(pk=2).first()
results = appliance_obj.coupons.all()
print(results)
# 反向查询之没有定义coupons = GenericRelation(to="Coupon")
result = models.Coupon.objects.filter(content_type=content, object_id=2)
print(result)
return HttpResponse("ok")
from django.db import models
class BookManger(model.Manger):
def title_count(self, keyword):
return self.filter(title__contains=keyword).count()
class Book(modles.Model):
...
object = BookManger() # 加一个管理器, 可能覆盖原来的管理器
使用时
Book.objects.title_count('django')
class MaleMager(models.Mager):
def get_queryset(self):
return super(MaleManger, self).get_queryset().filter(sex='M')
class FamaleMager(models.Manger):
def get_queryset(self):
return super().get_queryset().filter(sex='F')
class Person(models.Model):
people = models.Manger() # 默认的管理器
men = MaleManager()
women = FamaleMager()
使用时
xx.people.all()
xx.men.count()
iterator: 迭代数据
当queryset非常大时, 它一次获取一部分数据, 然后删除
objs = Book.objects.all().iterator()
for obj in objs:
print(obj.title)
for obj in objs:
print(obj.title)
# 第一正常有数据, 第二次没有结果, 因为第一次, 边遍历边删除, 第二次就没有结果了
就是说,查询数据库并不是实时的,如果查询过程中,数据库有增减,结果不会变,有缓存
print([a.create_time for a in model.Art.objects.all()])
如上, 数据库有变化时, 结果却相同, 因为有缓存
解决办法: 定义变量
queryset = models.Art.objects.all()
print([a.title for a in query])
from django.db.models import Q, F
Book.objects.all().update(price=F("price") + 10)
1)
ret = Book.objects.filter(Q(price=xx) | Q(name='xx'))
2)
from django.filter.models import Q
q = Q()
q.connection = "or" # 默认是and
q.children.append(("title", "XX")) # 可以传字符串形式的键
q.children.append(("price", "123"))
models.Tb1.objects.filter(q)
con = Q()
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2))
q1.children.append(('id', 3))
q2 = Q()
q2.connector = 'OR'
q2.children.append(('status', '在线'))
con.add(q1, 'AND')
con.add(q2, 'AND')
models.Tb1.objects.filter(con)
个人瞎鸡总结:
F能进行数学运算, Q对数据进行筛选
注意:
Book.objects.filter(Q(name='xx'), price=xx)
Q必须放在前面
Order._meta.app_label # ’app01‘, 能找到order表属于的app, 是一个字符串
Order._meta.model_name # 'order', 找到Order表的名字, 是一个字符串
field_obj = Order._meta.fields # 拿到所有字段
for i in field_obj:
print(i.verbose_name) # 要是字段没有这个属性返回字段名,多对多不打印
title = Order._meta.get_field('title') # 拿到Order表的title字段, 结果为app01.Order.title,
print(title.max_length) # 返回 32 返回的是title属性的值
Pulisher.objects.filter(id=2).update()
不能用get代替filter
from app001 import models
admin.site.register(models.Auth)
sex = models.BooleanField(max_length=1, choices=((0, '女'), (1, '男')), null=False)
m = models.ManyToManyField('Teacher', on_delete=models.CASCADE)
obj = class.objects.filter(id=1).first()
obj.m.add(2)
obj.madd(3)
obj.m.add([2, 3])
obj.m.remove([2, 3]) # 删除指定
obj.m.clear() # 清空全部
obj.m.set(2, 3, 4) # 全部重置
实时刷新, 不用重启django
from django import forms
from django.forms import widgets, fields
class A(forms.Form):
price = fields.IntegerField()
user_id = fields.IntegerField(
widget=widgets.Select()
# widget=widgets.Select(choices=models.Userinfo.objects.valuse_list('id', 'username'))
# 实际要查上面的, 但是每次最先加载__init__, 加载init时就已经查找完了, 在这里如果再查找就重复了
)
def __init__(self, *args, **kwargs):
super(A, self).__init__(*args, **kwargs)
self.fields['user_id'].widget.choices = models.Userinfo.objects.valuse_list('id', 'username')
在views.py中的form写法
class UserForm(forms.Form):
username = ModelChoiceField(queryset=models.UserInfo.objects.all(), to_field_name='指定在数据库的叫什么')
但是也带来了前端显示不正常的问题
所以要在models中加
from django.db import models
class UserInfo(models.Model):
username = models.CharField(max_length=33)
def __str__(self):
return self.username
后端传html, 也可以用模板的{{ | safe }}
from django.utils.safestring import mark_safe
def text(quest):
txt = "
$.ajax({
url: '',
type: 'POST',
data: {'k1': [1, 2, 3]},
dataType: 'JSON',
{#能将arg反序列化, 转化为js对象#}
traditional: true,
success: function (arg) {
}
})
$.ajax({
url: '',
type: 'POST',
data: {'k1': JSON.stringify({'a': 1})},
dataType: 'JSON',
{#能将arg反序列化, 转化为js对象#}
traditional: true,
success: function (arg) {
}
})
ajax 发送post请求默认会禁止
下面说几种跨域方法
{% csrf_token %}
就是input发送的ajax请求, 加个csrf_token
然后ajax把它发送过去
var il = $('#i2').val();
var csrfToken = $("[name='csrfmiddlewarewoken']").val();
$.ajax({
url: "",
type: "POST",
data: {'i1': i1, 'csrfmiddlewaretoken':csrfToken},
success: function (arf) {
}
})
直接在前端引入它
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
原理:通过
后端
def service(request):
func = request.GET.get('callbacks')
info = {'name': 'desky', 'age': 17}
return HttpResponse("%s('%s')" % func, json.dumps(info))
后端
def service(request):
info = {}
response = HttpResponse(json.dumps(info))
response["Access-Control-Allow-Origin"] = "*"
# "*"也可任意指定网址
return response
前端
正常发ajax就行了
from django import forms
from django.forms import widgets, fields
单选select(initial默认选2)
user = fields.CharField(initial=2, widget=widgets.Select(choices=((1, 'x'), (2, 'a'))))
# user = fields.ChoiceField(choices=(), widget=widgets.Select())
多选select(attrs 给它加属性)
user = fields.MultipleChoiceField(choices=(), widget=widgets.SelectMultiple(attrs={'class': ''}))
user = fields.CharField(widget=widgets.RadioSelect(choices=()))
# user = fields.ChoiceField(choices=(), widget=widgets.RadioSelect)
单选
user = fields.ChoiceField(widget=widgets.CheckboxInput(attrs=()))
多选
user = fields.MultipleChoiceField(choices=(), widget=widgets.CheckboxSelectMultiple)
model | Forms |
一对多 | forms.ModelChoiceField |
多对多 | forms.ModelMaltipleChiceField |
一对多的type:
多对多的type:
from django.forms.model import ModelChiceField
form = ModelFormDemo()
for bfield in form:
if istance(bfield.field, ModelChoiceField):
# 是否一对多字段
bfield.is_pop = True
# 对象可以 .xx给它加属性
'''
所以前端可以这样
{% if field.is_pop %}
可以判断是否是一对多, 多对多
'''
print(bfield.field.queryset.model)
# 打印
print(bfield.field.queryset.model._meta.model_name)
# Publish
作用于一对多和多对多
teacher = models.ManyToManyField(..., limit_choice_to = {"depart__in": [1002, 1005]})
相应的也可以在forms中
data = UserInfo.objects.filter(depart__in=[1002, 1005]) .values(''pk", "title")
tracher = forms.ModelMutichoice(choices=data)
class UserInfo(models.Model):
username = models.CharField(
null=True, # 数据库可以为空
db_column='user', # 把数据库默认的username字段改名为user
max_length=32,
db_index=True, # 加速查找
unique=True, # 不允许有重复值, 加速查找
)
pk = models.ForeignKey(
to="desky", # 和哪张表
to_field='id', # 和那个字段, 默认时id
related_name='b', # 方便反向查找, 反向查找时 .b 就行
# related_query_name='b', # 反向查找时, b_set
)
class A():
sex = models.IntegerField(choice=[(1, "男"),(0,"女")])
obj = A.objects.create(name='xx', sex=1)
print(obj.sex)
# 1
print(obj.get_Sex_display())
# 男
request.POST.getlist()
from django.views import View
class AddPublisher(View):
def get(self, request):
return ...
def post(self, request):
return ...
url
path('xx/', views.AddPublisher.as_view())
只是关掉了csrf验证
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def teacher..
为当前函数设置跨域请求
from django.views.decorators.csrf import csrf_protect
@csrf_protect
def teacher..
url(r'^book/([0-9]{2, 4})/ ([a-zA-Z]{2})/$', views.book)
后台(关键字参数)
def book(quest, arg1, arg2):
def book(request, *args):
url
url(r'^book/(?P[0-9]{2, 4})/(?P[a-zA-Z]{2})/$', views.book)
后台
def book(request, year, title):
def book(requesr, **kwargs):
from app01 import url as app01_urls
url(r'^app01/$', include(urls))
app01\urls.py
urlpatterns=[url(r'^book/', xxx)]
当url以app01开头时, 会被分配到app01/urls
# views.py
def test1(request):
def test2(request):
def test3(request):
# urls.py
urlpatterns = [
path('deskyaki/', ([
path('test1', test1),
path('test2', test2),
path('test3', test3),
], None, None))
]
urlpatterns = [
path('deskyaki/', ([
path('test1/', ([
path('test4', views.test4),
path('test05', views.test5),
], None, None)),
path('test2', views.test2)
], None, None))
]
urls.py
from django.contrib import admin
def get_urls():
temp = []
for model, admin_class_obj in admin.site._registry.items():
app_name = model._meta.app_label
model_name = model._meta.model_name
temp.append(path('{0}/{1}'.format(app_name, model_name), views.test4),)
return temp
urlpatterns = [
path('aki/', (get_urls(), None, None), )
]
# 可以访问类似如下的路径http://127.0.0.1:8088/aki/app001/blog
如 http://127.0.0.1:8088/aki/app001/blog/2/change/
urls.py
from django.urls import path, re_path
from django.contrib import admin
from django.shortcuts import HttpResponse
def list_view(request):
return HttpResponse('userindex')
def add_view(request):
return HttpResponse('user_add')
def change_view(request, id):
return HttpResponse('user_change')
def delete_view(request, id):
return HttpResponse('user_delete')
def get_urls2():
temp = []
temp.append(path('', list_view))
temp.append(path('/add/', add_view))
temp.append(re_path(r'/(\d+)/change/', change_view))
temp.append(re_path(r'/(\d+)/delete/', delete_view))
return temp
def get_urls():
temp = []
for model, admin_class_obj in admin.site._registry.items():
app_name = model._meta.app_label
model_name = model._meta.model_name
temp.append(path('{0}/{1}'.format(app_name, model_name), (get_urls2(), None, None)),)
return temp
urlpatterns = [
path('aki/', (get_urls(), None, None), )
]
url(r'^xx/$', views.xx, name='fanx_url')
点我
def xx(request):
redirect_url = reverse("fanx_yrl")
1) url
url(r'^book/(?P[0-9]{2, 4})/(?P[a-zA-Z]{2})/$', views.xx, name='fanx_url')
2) 模板(不管url是分组匹配还是分组命名匹配)
点我
3) 后台
当url是分组命名匹配时
def xx(request):
redirect_url = reverse('fanx_url', kwargs={'year': 2018, 'title': 'xx'})
当url时分组匹配时
redirect = reverse('fanx_url', args=[])
由于name没有作用域,Django 在反向解析url时,全局搜索,找到第一个name指定url时,立即返回。当我们在app中定义相同的name时,就要用到命名空间。
# app.urls
urlpatters = [
path('app01/', include('app01.urls', namespance='app01')),
path('app02/', include('app02.urls', namespance='app02')),
]
# app01.urls
urlpatters = [
path('index/', index, name='index'),
]
# app02.urls
urlpatters = [
path('index/', index, name='index'),
]
# views.py
from django.core.urlresovers import reverse
def index(request):
return HttpResponse(reverse('app01:index'))
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目的名字。settings")
import django
django.setup()
from app01 import models
books = models.Book.objects.all()
class Person(models.Model):
.....
def __str__(self):
return self.name
get() ---> aki
fileter()[0] --->
它们之间的其他区别
1. 输入参数:
get()的参数只是model中定义的些那字段
而filter()的参数可以是字段, 也可以是扩展的, where, in 等
2. 返回值
get()返回的是一个model对象
filter()返回的是一个新的Queryset对象
3. 异常
get()只有一条记录返回时候才正常, 也就说明get的查询字段必须是主键或者是唯一约束字段, 当返回多条记录或者没有找到时会 抛出异常。
filter() 有没有匹配到都不会抛出异常
ret = models.Person.objects.exclude(id=1)
返回一个Queryset对象, 里面类似字典
返回一个元组
ret = models.Perosn.objects.all().order_by("-birthday") 加了-表逆序, 不加正常排序
article_list = models.Article.objects.all().order_by("-weight_art", "-create_time")
加两个字段, 先按第一个排
ret = models.Person.objects.all().order_by("xx").reverse()
tag_list = models.Tag.objects.values('title').distinct()
filter(id__lt=10)
filter(id__gte=1) 大于等于
filter(id__gt=10)
filter(id__lte=1) 小于等于
filter(id__in=[11, 22, 33])
exclude(id__in=[11, 22, 33])
filter(name__contains='ven)
filter(name__icontains='ven') 不区分大小写
filter(id__range=[1,3])
models.objects.get(title__regex=r'^(An?|The)+') 匹配正则
models.objects.get(title__iregex=r'^(An?|The)+') 匹配不区分大小写的正则
models.User.objects.all().only('xx', 'xx') 只取那些字段
models.User.objexts.all().defer('xx', 'xx') 不取哪些字段
querysetlist = []
for i in resultlist:
querysetlist.append(Account(name=i))
# Account是一张表
Account.objects.bulk_create(querysetlist)
select:
ret = models.Person.objects.all().extra(select={"gt": "salary > 2000"})
"""
select (salary > 2000) as 'gt', 'person'. 'id',
'person'.'name', 'person'.'salary', 'person'.'dept_id' from 'persom';
"""
art = models.Article.objects.filter(nid=1).extra(
select={ "standard_time" : "strftime"('F%%Y-%%m-%%d', create_time)"}).values("standard_time", "nid")
where:
Person.objects.all().extra(where=["first || last like 'jeffrey %' "])
table:
Book.objects.all().extra(table=['myappp_person'], where=['last=author_last'])
# select * from myapp_book, myapp_person whrere last=author
params:
first_name = 'Joe'
person.objects.all().extra(where=["first='%s'"], params=[first_name])
对于一对一字段和多对一字段,它返回一个Queryset对象,它沿着外键关系查询关联对象,引起性能损耗,但以后使用外键时,则不需要数据库。对于一对多尽量用它,而不是prefetch_related()
class Article(models.Model):
category = models.Foreignkey('''')
class ArticleDetail(models.Model):
article = model.OneToOneField(.....)
articleList = model.Article.objects.select_related("category").all()
for article_obj in articleList:
print(artcle_obj.category.title)
就是顺着Article的外键,找到category的title。
select_related(depath=2) 加这个参数指定深度,不加默认 最大深度。
多外键: model.Article.objects.select_related("category","article").get(nid=1) 或
model.Article.objects.select_related("category").select_related("article")
原理: 相当于联表操作, inner join, 查询次数减少
对于多对多和一对多,查询每个表, 用python处理它们的关系
不使用它的情况
article_obj = models.Article.objects.all()
for i in article_obj:
print(i.tags.all())
用它
article_obj = models.Article.objects.prefetch_related("tags").all()
for i in article_obj:
print(i.tags.all())
all(), filter(), valuses(). values_list(), exclude(), order_by(), reverse(), distinct()
get(), first(), last()
exists()
count()
一些小实例
1)双下划线
models.Books.objects.filter(id=1).values("publisher__name") publisher是Book的外键字段
2)基于对象
book_obj=models.Book.objects.all().first()
ret=book_obj.publisher.name
python = models.Book.objects.filter(title='python').first()
ret = python.Publisher.email
1)基于对象 (小写表名_set())
pub_obj=models.Publisher.objects.all().first()
pub_obj.book_set().all()
pub_obj = models.Publisher.objects.filter(name=xx).first()
pub_obj.book_set().all()
for i in pub_obj:
print(i.title)
2) 基于双下划线
class Book(models.Model):
....
publisher = model,Foreignkey(to='Publisher', on_delete=models.CASCADE, related_name='books')
# related_name 反向查找的名称
ret=models.Publisher.objects.filter(id=1).values_list('books_title')
class Author(models.Model):
....
books = models.ManyToManyField(
to="Books", # 和哪张个表建立多对多关系
through="Author2Book", # 通过自己定义的第三张
through_fields=("author", "book") # 通过哪些字段, 注意顺序要和第三张表的的字段相同
)
class Author2Book(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(to='Author')
book = models.BooleanField(to="Book")
class Meta:
unique_together=[('author',"book")]
# 联合为一
from django.db import models
from django.db.models import Avg, Sum, Max, Min
ret = models.Book.objects.all().aggregate(Avg("price"))
ret = models.Book.objects.all().aggregate(price_avg=Avg("price"))
# 以字典形式返回
from django.db import models
ret = models.Book.objects.all().annotate(author_num=count("author"))
for book in ret:
print(book.title, book.count.num)
# 查询作者数量大于1的书
ret = models.Book.objects.all().annotate(author_num=count("author").filter(author_num__gt=1))
ret = models.Person.objects.values("dept_id").annotate(a=Avg('salary')).values("dept__name", "a")
"""
SELECT 'dept'.'name' , Avg('Person', 'salary') As 'a' Form 'Person' INNER JOIN 'dept'
ON ('person', 'dept') group by dept.id
"""
注意: aggregate ----> 字典 , annotate ----> queryset对象
response = redirect('/xxx/')
response = render(request, 'xx.html')
response.set_cookie('key', 'values') # 设置cookies 关闭浏览器就失效
# 设置cookies超过10秒失效,写法
response.set_cookie('key','value',max_age=10)
# 从登录10秒后失效,写法
current_time = datetime.datetime.utcnow()
current_data = current_time + datetime.timedelta(seconds=10)
response.set_cookie('key','value',expires=current_data)
response.set_signed_cookie(key,value,salt='加密盐',...)
return response # 别忘返回
request.COOKIES['key]
request.COOKIES.get('key')
response.delete_cookie('key')
主要说的存在数据库的session, dango的session默认是存在数据库的, 也就是说使用session之前要提交数据库
request.session['k1'] # 设置session
request.session.get('k1', None) # 拿session, 拿不到就返回空
request.session['k1'] = 123 # 重置session
request.session.setdefault('k1', 123) # 存在则不设置
del request.session['k1'] # 删除session
request.session.delete() # 只删除session
request.session.flush() # sesssion 和 cookie 全删
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 用户session的随机字符串
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
详情
https://www.cnblogs.com/zhuifeng-mayi/p/9099811.html
my_test.html
里面有两种ajxa跨域方式, 虽然注释掉了一种, 而且ajax的url,不写默认是给自己发ajax。当如果写了类似desky/之类域名,会在自己原来的url基础上加,如自己的url是aki,ajax的url是desky/, 则向aki/desky/发送请求
Title
{#{% csrf_token %}#}
后端
注意传给前端ajax的arg, 必须是json格式的,Httpresonse要先序列化, 用Jsonresponse如果传的不是字典,要加safe=False参数
def my_ajax(request):
if request.method == "POST":
data = request.POST.get('name')
print(data)
import json
a = json.dumps('adc')
# return HttpResponse(a)
return JsonResponse('abd', safe=False)
return render(request, 'my_test.html')
一共有5个,这里只说3个
在app同级下新建my_middleware.py
views.py
def index(request):
print('我是视图, 自己动')
return HttpResponse('ojbk')
my_middleware.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
MyURL = ['/']
class OX(MiddlewareMixin):
def process_request(self, request):
if request.path_info in MyURL:
print('这是request中间件')
return None
return HttpResponse('被拦住')
def process_view(self, request, view_func, view_args, view_kwargs):
print('这是views中间件')
print(request)
print(view_func.__name__)
print(view_args)
print(view_kwargs)
return None
# 返回none继续执行函数 然后执行中间件
# return HttpResponse('这是中间件的返回值')
# 不会执行函数,直接跳出,去执行process_response, 如果还有未执行的process_vies则也会直接跳过它们去执行process_response
def process_response(self, request, response):
print('这是response中间件')
# return HttpResponse('ok')
# Httpresponse覆盖了views的返回
return response
'''
[03/Jul/2019 17:59:47] "GET / HTTP/1.1" 200 4
这是request中间件
这是views中间件
index
()
{}
我是视图, 自己动
这是response中间件
'''
千万不要忘了:在settings的MIDDLEWARE中注册, ‘my_middleware.OX’
1) process_request(self, request)
执行顺序: 按照注册顺序,从上到下
返回值:返回None,继续执行; 返回response(Httpresponse)被拦截, 不会继续执行
2)process_response(self, request, response)
执行顺序: 按注册顺序的倒序, 从下到上
返回值: 必须返回response return response正常执行。 返回 Httpresponse则会覆盖函数的Httpresponse
3) process_views(self, request, view_func, view_args, view_kwargs)
何时执行: 在urls.py找到对应关系后, 在执行视图之前
执行顺序: 按注册顺序, 从上倒下
返回值: 返回None, 继续执行函数和其他中间件; 返回Httpresponse时,不会执行函数和其他的process_views中间件,
不过会接着着执行process_response.
在settings中
# 用户上传文件默认存在这个文件夹下
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
在url中设置,这样就可以通过浏览器访问url看到文件
from django.urls import re_path
from django.views.static import serve
from django.conf import settings
urlpatterns = [
re_path(r'^media/(?P.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
]
在Terminal中输入
python manage.py shell
from django.contrib.auth.hashers import make_password
make_password(‘明文密码’) 或者
make_password('明文密码',None, ‘指定加密算法’)
check_password('明文密码', '密文密码') 比较明密密码是否相同, 返回True或False
python manage.py shell
from django.contrib.auth.models import User
u = User.objects.get(username='xx')
u.set_password('明文密码')
u.save()