django提供了比较完善的后台数据库的接口,可供开发过程中调用和测试使用
django会搜集所有已注册的模型类,为这些模型类提供数据管理界面,供开发使用
该账号为管理后台最高权限账号
python3 manage.py createsuperuser
启动服务后,后台管理的登录地址:http://127.0.0.1:8000/admin,使用刚才注册的管理员账号登录即可
首先创建用户,在终端执行 python3 manage.py createsuperuser 命令
(testenv) [root@localhost mysite3]# python3 manage.py createsuperuser
用户名 (leave blank to use 'root'): root
电子邮件地址: [email protected]
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 里定义模型管理器类
绑定注册模型管理器和模型类
案例
修改 bookstore 应用下的 admin.py 文件,添加模型管理器类
from django.contrib import admin
from .models import Book
class 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内嵌类定义模型类的属性,用法如下:
修改 bookstore 应用下的 admin.py 文件,修改 Book 模型类
from django.db import models
class 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 模型管理类的自定义设置
在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:
一对一映射
一对多映射
多对多映射
一对一是表示现实事物间存在的一对一的对应关系
如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
语法:OneToOneField(类名, on_delete=xxx)
无外键的模型类[Author]:
有外键的模型类[Wife]:
直接通过外键属性查询,则称为正向查询
没有外键属性的一方,可以调用反向属性查询关联的另一方
一对多映射
反向关联属性为:实例对象.引用类名(小写),如作家的反向引用为:作家对象.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 models
class 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 models
class 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
>>> 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
>>> print(b1.title, b1.publisher.name)
python1 中信出版社
查询:反向查询
>>> from otm.models import *
>>> pub1 = Publisher.objects.get(name="中信出版社")
>>> pub1
>>> books = pub1.book_set.all()
>>> books
, ]>
>>> for book in books:
... print(book.title)
...
python1
python2
多对多表达对象之间多对多的复杂关系,如:每个都有不同的学校(小学,初中,高中……),每个学校都有不同的学生……
Mysql 中创建多对多需要依赖第三张表来实现
Django 中无需手动创建第三张表,这个操作Django自动完成
语法:在关联的两个类中的任意一个类中,增加:
用法示例:
一个作者可以出版多本图书
一本图书可以由多个作者共同编写
用法示例—创建模型类:
用法示例—创建数据
正向查询:有多对多属性的对象查另一方
通过 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 models
class 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
Django
cookies 是保存在客户端浏览器上的存储空间
在讲cookie前先了解下它的使用场景
使用Chrome浏览器打开京东网站且未登录情况下我的购物车未添加商品,所以商品数量是0
挑选3个商品加入购物车,此时购物车数量显示3
关闭 Chrome 浏览器再次打开京东首页发现购物车数量还是 3
如果此时换成 Firefox 浏览器打开京东首页发现购物车里的商品数量是 0
为什么 Chrome 浏览器未登录关闭浏览器后再次打开购物车商品数量没变,换个浏览器购物车商品数量就不是 3 了,这个场景就说明了 2 点
添加 cookies:修改 mysite3 下的 views.py 文件,添加指定视图函数
from django.shortcuts import render
from django.http import HttpResponse
def 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 views
urlpatterns = [
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 HttpResponse
def 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 resp
def 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 views
urlpatterns = [
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 变化
session 是在服务器上开辟了一段用于保留浏览器和服务器交互时的重要数据
向 INSTALLED_APPS 列表中添加
向 MIDDLEWARE 列表中添加
session 对象是一个类似与字典的 SessionStore 类型的对象,可以用类拟于字典的方式进行操作
session 能够存储如字符串,整型,字典,列表等数据
保存 session 的值到服务器
获取 session 的值
删除 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 views
urlpatterns = [
path('admin/', admin.site.urls),
# ......
path('set_cookies', views.set_cookies),
path('get_cookies', views.get_cookies),
path('set_session', views.set_session), # 设置session
path('get_session', views.get_session), # 获取session
]
启动服务:先测试 set 设置 session,然后再测试 get 获取 session
SESSION_COOKIE_AGE
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
注意:Django中的session数据存储在数据库中,所以使用session前需要确保已经执行过migrate操作将存储session表创建出来
django_session 表是单表设计;且该表数据量持续增加