ADMIN
- admin.py
把自己的模型类注册到管理后台
from django.contrib import admin
from .models import MyModel
# 注册自己的模型类
admin.site.register(MyModel)
模型管理器类
- admin.py
定义模型管理器类
class MyManager(admin.ModelAdmin):
# 自定义列表页显示的字段
list_display = ['id','f1','f2','f3']
# 修改跳转链接关联的字段
list_display_links = ['f1']
# 点击跳转显示自定义可编辑字段
# fields = ['f1','f2','f3']
# 和fields 二选一,fieldsets可以为字段添加面板头
fieldsets = [
(None, {'fields': ['title']}),
('出版社', {'fields': ['pub']}),
('Date information', {'fields': ['pub_date']}),
]
# 添加过滤器
list_filter = ['f2']
# 添加搜索框[模糊查询]
search_fields = ['title']
# 添加可在列表页编辑的字段
list_editable = ['price']
fieldsets
的效果
绑定注册模型管理器和模型类
from django.contrib import admin
from .models import *
admin.site.register(MyModel,MyManager)
# 绑定MyModel模型类到管理器类MyManager
管理后台模型类显示名称单,复数
class Meta:
db_table = 'book'
verbose_name = '图书'
verbose_name_plural = verbose_name
关系映射
一对一
synax:
OneToOneField(类名,on_delete=xxx)
class A(models.Model):
pass
class B(models.Model):
...
foto = models.OneToOneField(A, on_delete = models.CASCADE)
注意: 数据库中存储的foto
字段名称为foto_id
- 增
- 先创建一行a的数据
- 再创建b的数据
a1 = A.objects.create('f1'='xxx')
b1 = B.objects.create('f1'='yyy', foto=a1)
- 正查
- 先获取b对象
- 用
.
查询外键foto
的属性
b1=B.objects.get(f1='b1')
b1.foto.f1
- 反查
- 先获取a对象
- 用
.
查询被关联的B表类名的小写
,来获取一个b对象
a1=A.objects.get(f1='a1')
a1.b.f1
一对多
synax:
ForeignKey(类名,on_delete=xxx)
模型类结构和一对一 一样
class A(models.Model):
pass
class B(models.Model):
...
fotm = models.ForeignKey(A, on_delete = models.CASCADE)
- 增
- 先创建一行a的数据
- 再创建多行b的数据,关联到相同的外键
a1 = A.objects.create('f1'='xxx')
b1 = B.objects.create('f1'='yyy', fotm=a1)
b2 = B.objects.create('f1'='zzz', fotm=a1)
- 正查
- 同一对一,先获取b对象,再 用
.
查询外键fotm的属性
b1=B.objects.get(f1='b1')
b1.fotm.f1
- 同一对一,先获取b对象,再 用
- 反查
- 先获取a对象
- 通过
.关联类名小写_set
查询关联的属性,因为一对多,所以增加了一个_set
来获取一个objects
a1=A.objects.get(f1='a1')
a1.b_set.all()
- 删
- A中的外键a1被删除掉后,B中的多行数据都会被级联删除
- B中的数据删除了,不会影响A表数据
多对多
- mysql中多对多要依赖第三张表
- Django不需要第三张表,自动完成
synax:
ManyToManyField(类名)
class A(models.Model):
pass
class B(models.Model):
...
fmtm = models.ManyToMaynField(A)
- 正增
- 先创建一行b的数据
- 再通过b的外键,创建一行a的数据
- b也可以同时 绑定到其他 a
b1 = B.objects.create('f1'='yyy')
a1 = b1.fmtm.create('f1'='xxx')
b1.fmtm.add(a2)
- 反增
- 先创建多行a的数据
- 再创建一条b的数据
- 在把新建的b,绑定给其他a
a1 = A.objects.create('f1'='xxx1')
a2 = A.objects.create('f1'='xxx2')
b1 = a1.b_set.create('f1'='yyy')
a2.b_set.add(b1)
- 正查
- ,先获取b对象,再 用
.
查询外键fmtm, fmtm可以看做一个objects.
b1=B.objects.get(f1='b1')
b1.fmtm.all()
- ,先获取b对象,再 用
- 反查
- 先获取a对象
- 通过
.关联类名小写_set
查询关联的属性
a1=A.objects.get(f1='a1')
a1.b_set.all()
cookies和session
- js原生session操作
sessionStorage.setItem('key','value')
value = sessionStorage.getItem('key')
cookies
cookies是服务器发起请求,存储在客户端中的,所以设置cookies的方法,被封装进了HttpResponse
synax:
设置:
HttpResponse.set_cookie(key,value='',max_age=None, expires=None)
不指定max_age
和expires
时,关闭浏览器数据失效
max_age 设置过期时间,单位是秒
获取:
value = request.COOKIES.get('cookies名','默认值')
删除:
HttpResponse.delete_cookie(key)
views.py
def set_cookies(request):
resp = HttpResponse('set cookies is ok')
resp.set_cookie('uuid','jdj-kldjl-jd',500)
return resp
设置过期变量
from datetime import datetime,timedelta
expires = datetime.now()+timedelta(days=7))
session
session是客户端请求,服务器存储的,所以session被封装成了request中的一个字典
客户端只存一个sessionid.
服务器端根据客户端存储的sessionid去调对应的数据,返回给客户端
- 保存
request.session['key']=value
- 获取
request.session['key']
request.session.get('key',默认值)
- 删除
del request.session['key']
views.py
def set_session(request):
request.session['uuid'] = 'jdj-kldjl-jd'
return HttpResponse('set session is ok')
分页
django.core.paginator
paginator
的属性
- count: 需要分页数据的对象总数
- num_pages:分页后的页面总数
- page_range:从1开始的range对象,用于记录当前的页码数
- per_page:每页数据的个数
paginator
的方法
-
paginator.page(number)
- 属性
number
为页码信息 - 返回当前number页对应的信息,一个
page
对象 - 如果页码不存在,抛出InvalidPage异常
- 属性
-
page
对象属性
- object_list: 当前页上所有数据对象的列表
- number:当前页的序号,从1开始
- paginator:当前page对象相关的Paginator对象
方法
- has_next(): 有下一页,返回True
- has_previous():有上一页返回True
- has_other_pages(): 有上或下页 返回True
- next_page_number(): 返回下一页的页码,不存在,抛InvalidPage
- previous_page_number():返回上一页页码,不存在,抛InvalidPage
封装一个分页函数
views.py
# 封装一个分页函数
def my_paginator(object_list, request, per_page=8, nav_num=5):
# object_list: 传入的数据列表
# request: 请求
# per_page: 默认每页8条数据
# nav_num: 默认导航条标签数量5
paginator = Paginator(object_list, per_page)
# 取出当前需要暂时的页码, 默认为1
c_page = int(request.GET.get('page', 1))
if c_page < 1:
c_page = 1
if c_page > paginator.num_pages:
c_page = paginator.num_pages
# 取出当前页数据
try:
page = paginator.page(c_page)
except Exception as e:
print('exception: ', e)
page = paginator.page(1)
# 显示导航页数 5
if paginator.num_pages < nav_num + 1:
# 小于5页,全部显示
dis_range = range(1, paginator.num_pages + 1)
else: # 总页数,大于等于5页
if c_page + nav_num // 2 >= paginator.num_pages:
# 当前页+跨度>=总页数时
dis_range = range(c_page - nav_num // 2, paginator.num_pages + 1)
elif c_page - nav_num // 2 < 1:
# 当前页-跨度 <= 1时
dis_range = range(1, nav_num + 1 )
else:
dis_range = range(c_page - nav_num // 2, c_page + nav_num // 2 + 1)
rst = {'page': page, 'paginator': paginator, 'dis_range': dis_range}
print('dis_range: ', dis_range)
return rst
views.py
调用封装函数
def test_page(request):
# /test_page/4
# /test_page?page=1
page_num = request.GET.get('page', 1)
# 虚拟数据
all_data = []
for i in range(60):
all_data.append('a' + str(i))
rst = my_paginator(all_data, request, 8, 5)
return render(request, 'test_page.html', locals())
模板test_page.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>分页</title>
<link rel="stylesheet" href="{% static 'bootstrap/dist/css/bootstrap.css' %}">
</head>
<body>
<h1>BOOTSTRAP分页练习</h1>
{% for p in rst.page.object_list %}
<p>
{{ p }}
</p>
{% endfor %}
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if rst.page.has_previous %}
<li class="page-item">
<a class="page-link" href="/test_page?page={{ rst.page.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% for c_page in rst.dis_range %}
{% if rst.page.number == c_page %}
<li class="page-item active"><a class="page-link" href="/test_page?page={{ c_page }}">{{ c_page }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="/test_page?page={{ c_page }}">{{ c_page }}</a></li>
{% endif %}
{% endfor %}
{% if rst.page.has_next %}
<li class="page-item">
<a class="page-link" href="/test_page?page={{ rst.page.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
<a class="btn btn-info" href="/make_page_csv?page={{ rst.page.number }}">下载当前页数据</a>
<script src="{% static 'jquery.js' %}"></script>
<script src="{% static 'bootstrap/dist/js/bootstrap.js' %}"></script>
</body>
</html>
缓存页面
- 配置
settings.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table',
'TIMEOUT': 300, # 缓存保存时间 单位秒 ,默认值为300,
'OPTIONS': {
'MAX_ENTRIES': 300, # 缓存最大数据条数
'CULL_FREQUENCY': 2, # 缓存条数达到最大值时, 删除1/x的缓存数据
}
}
}
-
创建数据库缓存表
python manage.py createcachetable
-
给面页加装饰器
views.py
from django.views.decorators.cache import cache_page
@catch_page(30) ->单位s
def my_view(request):
...