admin后台管理
什么是admin后台管理
django提供了比较完善的后台数据库的接口,可供开发过程中调用和测试使用
django会搜集所有已注册的模型类,为这些模型类提供数据管理界面,供开发使用

admin配置步骤
创建后台管理账号
该账号为管理后台最高权限账号
-  python3 manage.py createsuperuser 
-   
-  测试登录启动服务后,后台管理的登录地址:http://127.0.0.1:8000/admin,使用刚才注册的管理员账号登录即可 实验:测试admin后台系统
-  首先创建用户,在终端执行 python3 manage.py createsuperuser 命令 
-  (testenv) [root@localhost mysite3]# python3 manage.py createsuperuser 用户名 (leave blank to use 'root'): root 电子邮件地址: root@qq.com Password: 123456 Password (again): 123456 密码长度太短。密码必须包含至少 8 个字符。 这个密码太常见了。 密码只包含数字。 Bypass password validation and create user anyway? [y/N]: y # 如果密码短需要手动确定 Superuser created successfully.启动服务 django 服务 
-  (testenv) [root@localhost mysite3]# python3 manage.py runserver后台管理的登录地址:http://127.0.0.1:8000/admin 
 
 
注册自定义模型类
若要自己定义的模型类也能在admin后台管理系统界面中显示和管理,需要将自己的类注册到后台管理界面
注册步骤
实验:绑定模型管理器类
-  在应用app中的 admin.py 中导入注册要管理的模型 models 类,如:from .models import Book 
-  调用 admin.site.register 方法进行注册,如:admin.site.register(自定义模型类) 
-  案例 
-   
-  修改自定义模型类的数据样式 
-  admin后台管理数据库中对自定义的数据记录都展示为 XXX object 类型的记录,不便于阅读和理解 
-  在用户自定义的模型类中可以重写 def str(self)方法解决显示问题,如: 
-   
-  实验:注册模型类
-  修改 bookstore 应用下的 admin.py 文件 
-  from django.contrib import admin from .models import Book # 导入模型类# Register your models here. admin.site.register(Book) # 注册模型类启动服务,重新登录 admin 后台管理系统,观察界面 
-   
-  点击Books链接,查看图书详情页 
-   
-  这里显示的内容是 __str__方法封装的字符串,所以可以自定义修改
-  模型管理器类理解与说明作用:为后台管理界面添加便于操作的新功能 说明:后台管理器类须继承自 Django.contrib.admin 里的 ModelAdmin 类 使用方法
-  在 <应用app>/admin.py 里定义模型管理器类 
-   
-  绑定注册模型管理器和模型类 
-   
-  案例 
-   
-  类属性说明
- list_display:去控制哪些字段会显示在admin后台管理的修改列表页面中
- list_display_links:可以控制list_display中的字段是否应该链接到对象的”更改”页面
-  修改 bookstore 应用下的 admin.py 文件,添加模型管理器类 
- list_filter:设置激活admin修改列表页面右侧栏中的过滤器
- search_fields:设置启用admin更改列表页面上的搜索框
-  from django.contrib import admin from .models import Bookclass BookManager(admin.ModelAdmin):# 列表页显示哪些字段的列list_display = ["id", "title", "pub", "price"]# 控制 list_display 中的字段,哪些可以链接到修改页list_display_links = ["title"]# 添加过滤器list_filter = ["pub"]# 添加搜索框[模糊查询]search_fields = ["title"]# 添加可在列表编辑的字段list_editable = ["price"]admin.site.register(Book, BookManager) # 将模型管理器类和模型类进行绑定启动服务,重新登录 admin 后台管理系统,观察界面 
-   
-  点击Books进入详情页,发现修改内容均已在管理界面生效 
-   
-  Meta类通过Meta内嵌类定义模型类的属性,用法如下: 
-   
实验:修改Meta类属性
-  修改 bookstore 应用下的 admin.py 文件,修改 Book 模型类 
from django.db import modelsclass Book(models.Model):title = models.CharField("书名", max_length=50, default="", unique=True)pub = models.CharField("出版社", max_length=50, default="")price = models.DecimalField("定价", max_digits=7, decimal_places=2, default=0.0)market_price = models.DecimalField("零售价", max_digits=7, decimal_places=2, default=0.0)is_active = models.BooleanField("是否活跃", default=True)def __str__(self):return f"{self.title}, {self.pub}, {self.price}, {self.market_price}"class Meta:db_table = "book"verbose_name = "图书"  # 修改单数显示verbose_name_plural = verbose_name  # 修改复数显示启动服务,重新登录 admin 后台管理系统,观察界面

练习
需求:对 Author 模型管理类的自定义设置
- 将 Author 模型类加入后台管理
- 制作一个 AuthorManager 管理器类,让后台管理 Authors 列表中显示作者的 ID、姓名、年龄信息
- 用后台管理程序添加三条 Author 记录
- 修改其中一条记录的年龄 – Author
- 删除最后一条添加的记录 – Author
总结
- 注册自己的模型类
- 修改自定义模型类的显示样式 - 模型管理器类
- Meta类对模型类的属性修改
关系映射
什么是关系映射
在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:
-  一对一映射 - 如:一个身份证对应一个人
 
-  一对多映射 - 如:一个班级可以有多个学生
 
-  多对多映射 
- 如:一个学生可以报多个课程,一个课程可以有多个学生学习
一对一映射
概念与理解
创建模型类
查询数据
正向查询
-  一对一是表示现实事物间存在的一对一的对应关系 
-  如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等 
-  语法:OneToOneField(类名, on_delete=xxx) 
-   
-  特殊字段选项【必须】on_delete:级联删除
- models.CASCADE 级联删除:Django模拟 SQL 约束 ON DELETE CASCADE 的行为,并删除包含 ForeignKey的对象
- Models.PROTECT:抛出 ProtectedError 以阻止被引用对象的删除;等同于 mysql 默认的 RESTRICT
- SET_NULL 设置 ForeignKey null;需要指定 null = True
- SET_DEFAULT:将 ForeignKey 设置为其默认值,必须设置 ForeignKey 的默认值
- 示例 - 创建模型类 – oto/models.py
 
-  添加数据
-  无外键的模型类[Author]: - author1 = Author.objects.create(name="王老师")
 
-  有外键的模型类[Wife]: - 方式1:wife1 = Wife.objects.create(name="王夫人", author=author1) # 关联王老师对象
- 方式2:wife1 = Wife.objects.create(name="王夫人", author_id=1) # 关联王老师对应的主键值
 
-  直接通过外键属性查询,则称为正向查询 
-   
反向查询
没有外键属性的一方,可以调用反向属性查询关联的另一方
一对多映射
-  反向关联属性为:实例对象.引用类名(小写),如作家的反向引用为:作家对象.wife 
-  当反向引用不存在时,则会触发异常 
-  author1 = Author.objects.get(name=‘王老师’) author1.wife.name实验:一对一模型
-  创建应用:oto 
-  (testenv) [root@localhost mysite3]# python3 manage.py startapp oto并在 settings.py 中将 oto 应用进行注册 
-  INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','music','news','sport','bookstore','oto', # 模型注册 ]修改 oto 应用下的 models.py,创建模型类 
-  from django.db import modelsclass Author(models.Model):# wife 反向属性:用作反向查询name = models.CharField('姓名', max_length=11)class Wife(models.Model):name = models.CharField('姓名', max_length=11)author = models.OneToOneField(Author, on_delete=models.CASCADE)同步迁移数据库 
-  (testenv) [root@localhost mysite3]# python3 manage.py makemigrations (testenv) [root@localhost mysite3]# python3 manage.py migrate进入 MySQL 环境,观察 wife 表中的外键,自动生成 author_id 外键 
-  (testenv) [root@localhost mysite3]# mysql -uroot -p123456 MariaDB [(none)]> USE mysite3; MariaDB [mysite3]> DESC oto_author; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(11) | NO | | NULL | | +-------+-------------+------+-----+---------+----------------+MariaDB [mysite3]> DESC oto_wife; +-----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(11) | NO | | NULL | | | author_id | int(11) | NO | UNI | NULL | | +-----------+-------------+------+-----+---------+----------------+测试:给两张表中添加数据,使用 Django Shell 的方式,两种方式添加数据 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from oto.models import * >>> a1 = Author.objects.create(name="ben") >>> w1 = Wife.objects.create(name="benfuren", author=a1) # 类属性赋值 >>> a2 = Author.objects.create(name="niu") >>> w2 = Wife.objects.create(name="niufuren", author_id=2) # 数据库字段赋值 >>> a2.id # 查看作者id 2查询:正向查询 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from oto.models import * >>> wife = Wife.objects.get(name="benfuren") >>> wife.name 'benfuren' >>> wife.author.name 'ben'查询:反向查询 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from oto.models import * >>> author1 = Author.objects.get(name="ben") >>> author1.wife.name # 利用反向属性进行数据查询 'benfuren'一对一映射关系总结
-  一对一的模型类创建 
-  一对一的数据创建 
-  一对一的数据查询 - 正向查询
- 反向查询
 
概念与理解
一对多是表示现实事物存在的一对多的对应关系
如:一个学校有多个班级,一个班级有多个学生,一本书只能属于一个出版社,但是出版社可以出版多本书
一对多需要明确出具体角色,在多表上设置外键
创建模型类
-  语法:当一个A类对象可以关联多个B类对象时 
-   
-  ForeignKey必须指定 on_delete 模式 
-  示例 – 创建模型类 - otm/models.py 
-   
-  添加数据
-  先创建“一”再创建多“多” 
-  示例: 
-  from .models import * pub1=Publisher.objects.create(name='清华大学出版社') Book.objects.create(title='C++', publisher=pub1) Book.objects.create(title='Java', publisher_id=1)查询数据
-  正向查询 [通过Book查询Publisher] 
-   
-  反向查询 [通过Publisher查询对应的所有的Book] 需要用到 反向属性 
-   
-  实验:一对多模型
-  创建应用:otm 
-  (testenv) [root@localhost mysite3]# python3 manage.py startapp otm并在 settings.py 中将 otm 应用进行注册 
-  INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','music','news','sport','bookstore','oto','otm', # 模型注册 ]修改 otm 应用下的 models.py,创建模型类 
-  from django.db import modelsclass Publisher(models.Model):#出版社 [一]name = models.CharField('出版社名称', max_length=50)class Book(models.Model):#书名 [多]title = models.CharField('书名', max_length=11)publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) # 外键同步迁移数据库 
-  (testenv) [root@localhost mysite3]# python3 manage.py makemigrations (testenv) [root@localhost mysite3]# python3 manage.py migrate进入 MySQL 环境,观察 Book 表中的外键 
-  (testenv) [root@localhost mysite3]# mysql -uroot -p123456 MariaDB [(none)]> USE mysite3; MariaDB [mysite3]> DESC otm_book; +--------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(11) | NO | | NULL | | | publisher_id | int(11) | NO | MUL | NULL | | +--------------+-------------+------+-----+---------+----------------+MariaDB [mysite3]> DESC otm_publisher; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(50) | NO | | NULL | | +-------+-------------+------+-----+---------+----------------+测试:给两张表中添加数据,使用 Django Shell 的方式,先创建一,再创建多 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from otm.models import * >>> p1 = Publisher.objects.create(name="中信出版社") >>> p1 <Publisher: Publisher object (1)> >>> b1 = Book.objects.create(title="python1", publisher=p1) # 类属性赋值 >>> b2 = Book.objects.create(title="python2", publisher_id=1) # 数据库字段赋值查询:正向查询 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from otm.models import * >>> b1 = Book.objects.get(id=1) >>> b1 <Book: Book object (1)> >>> print(b1.title, b1.publisher.name) python1 中信出版社查询:反向查询 
-  >>> from otm.models import * >>> pub1 = Publisher.objects.get(name="中信出版社") >>> pub1 <Publisher: Publisher object (1)> >>> books = pub1.book_set.all() >>> books <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]> >>> for book in books: ... print(book.title) ... python1 python2多对多映射概念与理解
-  多对多表达对象之间多对多的复杂关系,如:每个都有不同的学校(小学,初中,高中……),每个学校都有不同的学生…… 
-  Mysql 中创建多对多需要依赖第三张表来实现 
-  Django 中无需手动创建第三张表,这个操作Django自动完成 
-  语法:在关联的两个类中的任意一个类中,增加: - 属性 = models.ManyToManyField(MyModel)
 
-  创建模型类用法示例: 
-  一个作者可以出版多本图书 
-  一本图书可以由多个作者共同编写 
-   
-  用法示例—创建模型类: 
-   
-  添加数据
-  用法示例—创建数据 
-   
-  数据查询正向查询:有多对多属性的对象查另一方 
-  通过 Book 查询对应的所有的 Author 
-  此时多对多属性相当于 objects 
-   
-  反向查询: 
-  通过 Author查询对应的所有的 Book 
-  利用反向属性 book_set 
-   
-  实验:多对多模型
-  创建应用:mtm 
-  (testenv) [root@localhost mysite3]# python3 manage.py startapp otm并在 settings.py 中将 mtm 应用进行注册 
-  INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','music','news','sport','bookstore','oto','otm','mtm', # 模型注册 ]修改 mtm 应用下的 models.py,创建模型类 
-  from django.db import modelsclass Author(models.Model):name = models.CharField('姓名', max_length=11)class Book(models.Model):title = models.CharField('书名', max_length=11)authors = models.ManyToManyField(Author)同步迁移数据库 
-  (testenv) [root@localhost mysite3]# python3 manage.py makemigrations (testenv) [root@localhost mysite3]# python3 manage.py migrate进入 MySQL 环境,观察 Django 帮助我们生成的中间表 
-  (testenv) [root@localhost mysite3]# mysql -uroot -p123456 MariaDB [(none)]> USE mysite3; MariaDB [mysite3]> DESC mtm_author; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(11) | NO | | NULL | | +-------+-------------+------+-----+---------+----------------+MariaDB [mysite3]> DESC mtm_book; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(11) | NO | | NULL | | +-------+-------------+------+-----+---------+----------------+MariaDB [mysite3]> DESC mtm_book_authors; # 中间表 +-----------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | book_id | int(11) | NO | MUL | NULL | | | author_id | int(11) | NO | MUL | NULL | | +-----------+---------+------+-----+---------+----------------+测试:给两张表中添加数据,使用 Django Shell 的方式 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from mtm.models import * # 方案1:先创建 author,再关联 book >>> author1 = Author.objects.create(name="teacher ben") >>> author2 = Author.objects.create(name="teacher niu") >>> book1 = author1.book_set.create(title="Python") >>> author2.book_set.add(book1) # 方案2:先创建 book,再关联 author >>> book2 = Book.objects.create(title="Django") # 凯哥和niu老师都参与了Django的编写 >>> author3 = book2.authors.create(name="kaige") >>> book2.authors.add(author2)查询:正向查询,通过 Book 查询对应的所有的 Author 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from mtm.models import * >>> book1 = Book.objects.get(title="Django") >>> book1.title 'Django' >>> users = book1.authors.all() >>> for user in users: ... print(user.name) ... teacher niu kaige查询:反向查询 
-  (testenv) [root@localhost mysite3]# python3 manage.py shell >>> from mtm.models import * >>> author2 = Author.objects.get(name="teacher niu") >>> books = author2.book_set.all() >>> for book in books: ... print(book.title) ... Python DjangoCookies 和 Session会话概念
- 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话
- HTTP 协议是无状态的,导致会话状态难以保持
- 试想一下,如果不保持会话状态,再电商网站购物的场景体验?
- Cookies和Session就是为了保持会话状态而诞生的两个存储技术
Cookies
Cookies 定义
cookies 是保存在客户端浏览器上的存储空间
Cookie 使用场景
在讲cookie前先了解下它的使用场景
-  使用Chrome浏览器打开京东网站且未登录情况下我的购物车未添加商品,所以商品数量是0 
-   
-  挑选3个商品加入购物车,此时购物车数量显示3 
-   
-  关闭 Chrome 浏览器再次打开京东首页发现购物车数量还是 3 
-  如果此时换成 Firefox 浏览器打开京东首页发现购物车里的商品数量是 0 
-  为什么 Chrome 浏览器未登录关闭浏览器后再次打开购物车商品数量没变,换个浏览器购物车商品数量就不是 3 了,这个场景就说明了 2 点 
- 商品信息保留在本地了,未保留在浏览器缓存
- 不同的浏览器cookie的保留路径不一样,并且各个浏览器的cookie信息互不影响
Cookies 特点
Django 中的 cookie



- cookie 在浏览器上是以键值对的形式进行存储的,键和值都是以 ASCII 字符串的形式存储(不能是中文字符串)
- 存储的数据带有声明周期
- cookie 中的数据是按域存储隔离的,不同的域之间无法访问
- cookie 的内部的数据会在每次访问此网站时携带到服务器端,如果 cookie 过大会降低响应速度
实验:Cookies 操作
-  添加 cookies:修改 mysite3 下的 views.py 文件,添加指定视图函数 
-  from django.shortcuts import render from django.http import HttpResponsedef test_static(request):return render(request, "test_static.html")def set_cookies(request): # 添加测试cookie的函数resp = HttpResponse('set cookies is ok')resp.set_cookie('uuname', 'nfx',500)return resp修改主路由 urls.py 
-  from django.contrib import admin from django.urls import path, include from . import viewsurlpatterns = [path('admin/', admin.site.urls),# ......path('set_cookies', views.set_cookies), ]启动服务,测试 http://127.0.0.1:8000/set_cookies,观察网络请求中的 cookies 变化 
-   
-  获取 cookies:修改 mysite3 下的 views.py 文件,添加指定视图函数 
-  from django.shortcuts import render from django.http import HttpResponsedef test_static(request):return render(request, "test_static.html")def set_cookies(request):resp = HttpResponse('set cookies is ok')resp.set_cookie('uuname', 'nfx',500)return respdef get_cookies(request): # 添加获取cookie的函数value = request.COOKIES.get('uuname')return HttpResponse(f'value is {value}')修改主路由 urls.py 
-  from django.contrib import admin from django.urls import path, include from . import viewsurlpatterns = [path('admin/', admin.site.urls),# ......path('set_cookies', views.set_cookies),path('get_cookies', views.get_cookies), # 获取cookie的url ]启动服务,测试 http://127.0.0.1:8000/get_cookies,观察网络请求中的 cookies 变化 
-   
-  SessionSession概念session 是在服务器上开辟了一段用于保留浏览器和服务器交互时的重要数据 
-  实现方式
- 使用session需要在浏览器客户端启动 cookie,且在cookie中存储 sessionid
- 每个客户端都可以在服务端有一个独立的 session
- 注意:不同的请求者之间不会共享这个数据,与请求者一一对应
在 Django 中的配置
向 INSTALLED_APPS 列表中添加

向 MIDDLEWARE 列表中添加
 
 
session的使用
-  session 对象是一个类似与字典的 SessionStore 类型的对象,可以用类拟于字典的方式进行操作 
-  session 能够存储如字符串,整型,字典,列表等数据 
-  保存 session 的值到服务器 
-  - request.session['KEY'] = VALUE
 
-  获取 session 的值 - value = request.session['KEY']
- value = request.session.get('KEY', '默认值')
 
-  删除 session - del request.session['KEY']
 
实验:Session 操作
-  添加以及获取 session:修改 mysite3 下的 views.py 文件,添加指定视图函数 
-  def set_session(request):request.session['uname'] = 'nfx'return HttpResponse('set session is ok')def get_session(request):value = request.session['uname']return HttpResponse(f'session value is {value}')修改主路由 urls.py 
-  from django.contrib import admin from django.urls import path, include from . import viewsurlpatterns = [path('admin/', admin.site.urls),# ......path('set_cookies', views.set_cookies),path('get_cookies', views.get_cookies),path('set_session', views.set_session), # 设置sessionpath('get_session', views.get_session), # 获取session ]启动服务:先测试 set 设置 session,然后再测试 get 获取 session 
-   
-  settings.py 中相关配置项以及注意事项
-  SESSION_COOKIE_AGE 
- 作用:指定sessionid在cookies中的保存时长 (默认时2周),如下:
- 例如:SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
-  SESSION_EXPIRE_AT_BROWSER_CLOSE = True 
- 设置只要浏览器关闭时,session就失效(默认是False)
-  注意:Django中的session数据存储在数据库中,所以使用session前需要确保已经执行过migrate操作将存储session表创建出来 
-  django_session 表是单表设计;且该表数据量持续增加 - 可以定期执行 python3 manage.py clearsessions
- 该命令可删除已过期的 session 数据
 
Cookie和Session的对比
