admin后台管理与数据库关系映射
1. admin管理后台
django提供了一个较为完整的后台管理数据的平台,可以将所有注册的模型类加载到admin管理后台,用户在登录后可对数据进行可视化管理。
首先执行python manage.py createsuperuser命令,创建一个超级用户,该用户拥有对系统的最高管理权限。
创建用户后访问127.0.0.1:8000/admin,使用创建的用户登录进入admin管理后台,可在后台增加用户、组、管理用户权限等。
例如,管理用户:
对自己创建的模型类,可以在其对应的应用目录下的admin.py中注册,注册后即可在admin后台中管理。
注册需要调用admin.site.register()方法
admin.site.register(Book)
admin.site.register(Author)
注册之后就可以在后台看到相关数据
通过两个图片,可以看出系统自带的对用户的管理与我们注册的模型类显示效果差的太多,我们自己注册的Book类,信息显示非常乱。对于这个问题,可以在注册模型类时绑定模型管理器xxxManager,使用模型管理器管理模型类,如:
# Book类的模型管理器
class BookManager(admin.ModelAdmin):
list_display = ['id', 'title', 'pub', 'price', 'market_price']
# Author类的模型管理器
class AuthorManager(admin.ModelAdmin):
list_display = ['id', 'name', 'age']
# 注册模型管理器和模型类
admin.site.register(Book, BookManager)
admin.site.register(Author, AuthorManager)
模型管理器中的list.display[‘属性1’,‘属性2’…],就是让admin后台列表页可以显示那些字段,上述效果如下:
这里显示的“书名”,“出版社”,“定价”等抬头信息,是我们在创建模型类时所指定的verbose_name,也就是字段第一个参数
除了list_display,模型管理器还提供了其他选项来控制模型类的显示
- list_display:控制那些字段显示在admin修改页面
- list_display_link:控制list_display中的字段是否可链接到相应对象的“更改”页面
- list_filter:设置激活admin侧栏中的过滤器
- search_fields:设置启动admin更改列表上的搜索框
- list_editable:设置模型类的字段是否允许在修改页面直接更改
class BookManager(admin.ModelAdmin):
# 显示哪些字段
list_display = ['id', 'title', 'pub', 'price', 'market_price']
# list_display的哪些字段可链接
list_display_links = ['title']
# 添加过滤器
list_filter = ['pub']
# 添加搜索框(模糊搜索)
search_fields = ['title']
# list_display中哪些字段可直接编辑,该字段需与list_display_links中的字段互斥
list_editable = ['price']
效果如下:
2. 数据库关系映射
关系型数据库中常见的有三种映射:
- 一对一映射:一个学生对应一个学号
- 一对多映射:一个班级有多个学生
- 多对多映射:一个学生可以学习多门课程,一门课程有多个学生学习
2.1 一对一映射
语法:使用models的OneToOneField方法,必须要设置级联方式on_delete,
例如模型A和B是一对一的关系:
class A(models.Model):
...
class B(models.Model):
# B的属性1受A相应属性的约束
属性1 = models.OneToOneField(A, on_delete=models.CASCADE)
on_delete级联有以下几种设置方式:
- models.CASCADE:级联删除,与数据库的类似
- models.PROTECT:抛出ProtectedError阻止删除,类似数据库的RESTRICT选项
- SET_NULL:设置外键ForeignKey为空,需要指定该列允许为空(null=True)
- SET_DEFAULT:设置外键为默认值,需要在创建模型类时指定该属性的默认值(default=xxx)
一对一创建数据的方式:
author1 = Author.objects.create(name='刘老师')
# 方式一:关联author实体对象
wife1 = Wife.objects.create(name='刘夫人', author=author1)
#方式二:关联author对应的主键
wife2 = Wife.objects.create(name='刘夫人', author_id=1)
一对一正向查询:通过外键值查询对应主键的对象
wife = wife.objects.get(name='刘夫人')
print(wife.name, '的丈夫是', wife.author.name)
一对一反向查询:没有外键属性的一方,反向查询到关联的另一方
author = wife.objects.get(name='刘老师')
print('刘老师的夫人是', author.wife.name)
2.2 一对多映射
语法:一个A类对象可以关联多个B类对象,则在B类应使用models.ForeignKey()方法指定外键,即一对多模型需要在“多”的一方定义模型类时指定映射关系,此外还要注意必须指定on_delete模式,模式取值与一对一映射相同。
例如出版社和书的关系,一个出版社可出版多本书,一本书只能有一个出版社,如下:
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)
一对多创建数据:先创建“一”的对象,再创建“多”的对象,具体创建方式也有两种,一种直接绑定对象,一种绑定对象对应的主键值
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,可以直接通过“多”对象的“.”操作获取绑定的“一”对象
# 直接通过book实体对象获取,即book.publisher
book = Book.objects.get(id=1)
print(book.title,"的出版社是", book.publisher.name)
一对多反向查询:通过Publisher对象查询对应的所有Book对象,需要用到反向属性,采用类名小写_set的方式,如book_set,等同于正向查询的objects,通过book_set调用方法
# 方式一
pub1 = Publisher.objects.get(name="工业出版社")
books_1 = pub1.book_set.all()
# 方式二
books_2 = Book.objects.filter(publisher=pub1)
2.3 多对多映射
语法:多对多映射关系复杂,对属性使用models.ManyToManyField()方法建立映射,在Mysql中创建两个数据表的多对多映射需要依赖第三张表,这张表由django自动创建,如定义模型类Author和Book
class Author(models.Model):
name = models.CharField('姓名', max_length=11)
class Book(models.Model):
title = models.CharField('书名', max_length=11)
author = models.ManyToManyField(Author)
迁移同步到数据库中,可以发现django生成了三张表
多对多创建数据:两种方案,一种是先创建author再关联book,一种是先创建book再关联author
# 方案1 先创建author再关联book
author1 = Author.objects.create(name='李老师')
author2 = Author.objects.create(name='王老师')
# 两位老师共同编写书籍
# 首先用一个老师的实体对象反向创建书本实体对象
book1 = author1.book_set.create(title='django基础教学')
# 再绑定另一位老师
authr2.book_set.add(book1)
# 方案2 先创建book再关联author
book = Book.objects.create(title='django进阶教学')
# 由李老师和另一位刘老师编写
author3 = book.objects.create(name='刘老师')
# 绑定李老师(author1)
book.authors.add(author1)
多对多正向查询:有多对多属性的对象查询另一方
如,通过Book查询对应的所有Author,此时多对多属性相当于objects
# 获取book对应的所有author
book.authors.all()
# 获取book年龄大于50岁的作者信息
book.authors.filter(age__gt=50)
从上面可以看出,正向查询时,多对多属性可以像对象管理器objects一样调用各种方法查询
多对多反向查询:
通过没有多对多属性的一方查询另一方,例如通过Author查询对应的所有Book,此时应利用反向属性book_set
author.book_set.all()
author.book_set.filter(条件...)