Admin后台管理

  • django 提供了比较完善的后台管理数据库的接口,可供开发过程中调用和测试使用
  • django 会搜集所有已注册的模型类,为这些模型类提拱数据管理界面,供开发者使用
  1. 创建后台管理帐号
  • 根据提示完成注册,参考如下
$ python3 manage.py createsuperuser
Username (leave blank to use 'tarena'): tarena  # 此处输入用户名
Email address: laowei@tedu.cn  # 此处输入邮箱
Password: # 此处输入密码(密码要复杂些,否则会提示密码太简单)
Password (again): # 再次输入重复密码
Superuser created successfully.
  1. 用注册的帐号登陆后台管理界面

注册自定义模型类

  • 若要自己定义的模型类也能在 /admin 后台管理界中显示和管理,需要将自己的类注册到后台管理界面
  • 添加自己定义模型类的后台管理数据表的,需要用admin.site.register(自定义模型类) 方法进行注册
  1. 在应用app中的admin.py中导入注册要管理的模型models类
from .models import Book
  1. 调用 admin.site.register 方法进行注册
from django.contrib import admin
admin.site.register(自定义模型类)
  • 如: 在 bookstore/admin.py 添加如下代码对Book类进行管理
# file: bookstore/admin.py
from django.contrib import admin
# Register your models here.

from . import models
...
admin.site.register(models.Book)  # 将Book类注册为可管理页面

修改自定义模型类的展现样式

  • 在admin后台管理数据库中对自定义的数据记录都展示为 XXXX object 类型的记录,不便于阅读和判断
  • 在用户自定义的模型类中可以重写 def __str__(self): 方法解决显示问题
  • 在 自定义模型类中重写__str__(self)方法返回显示文字内容
class Book(models.Model):
    title = models.CharField("书名", max_length=50, default='',unique=True)
    price = models.DecimalField('定价', max_digits=7, decimal_places=2, default=0.0)
    pub = models.CharField('出版社',null=False,default='',max_length=20)
    market_price = models.DecimalField('零售价', max_digits=7, decimal_places=2, default=0.0)
    isactive = models.BooleanField('是否上架',default=True)

    def __str__(self):
        return "书名" + self.title

模型管理器类

  • 为后台管理界面添加便于操作的新功能
  • 后台管理器类须继承自 django.contrib.admin 里的 ModelAdmin
  1. <应用app>/admin.py 里定义模型管理器类
class XXXXManager(admin.ModelAdmin):
    ......
  1. 绑定注册模型管理器和模型类
from django.contrib import admin
from .models import *
admin.site.register(YYYY, XXXXManager) # 绑定 YYYY 模型类与 管理器类 XXXXManager
  1. 或者使用装饰器进行注册模型管理器和模型类
from django.contrib import admin

# Register your models here.
from django.core.cache import caches

from goods.models import SKU

@admin.register(SKU)
class SKUAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        super().save_model(request, obj, form, change)
        caches['goods_index'].clear()

admin.site.register(SKU,SKUAdmin)

QQ截图20230403163516.jpg

  • 示例
# file : bookstore/admin.py
from django.contrib import admin
from .models import Book

class BookManager(admin.ModelAdmin):
    list_display = ['id', 'title', 'price', 'market_price']

admin.site.register(Book, BookManager)
  • 进入http://127.0.0.1:8000/admin/bookstore/book/查看显示方式和以前有所不同

  • 模型管理器类ModelAdmin中实现的高级管理功能

  1. list_display 去控制哪些字段会显示在Admin 的修改列表页面中。
  2. list_display_links 可以控制list_display中的字段是否应该链接到对象的“更改”页面。
  3. list_filter 设置激活Admin 修改列表页面右侧栏中的过滤器
  4. search_fields 设置启用Admin 更改列表页面上的搜索框。
  5. list_editable 设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑。
  6. 其它参见https://docs.djangoproject.com/en/2.2/ref/contrib/admin/

再谈Meta类

  • 模型类可以通过定义内部类class Meta 来重新定义当前模型类和数据表的一些属性信息
class Book(models.Model):
    title = CharField(....)
    class Meta:
        db_table = '数据表名'
        # 该模型所用的数据表的名称。(设置完成后需要立马更新同步数据库)
        verbose_name = '单数名'
        # 给模型对象的一个易于理解的名称(单数),用于显示在/admin管理界面中
        verbose_name_plural = '复数名'
        # 该对象复数形式的名称(复数),用于显示在/admin管理界面中

数据表关联关系映射

常用的表关联方式有三种

  1. 一对一映射
  • 如: 一个身份证对应一个人
  1. 一对多映射
  • 如: 一个班级可以有多个学生
  1. 多对多映射
  • 如: 一个学生可以报多个课程,一个课程可以有多个学生学习

一对一映射

  • 一对一是表示现实事物间存在的一对一的对应关系。
  • 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
class A(model.Model):
    ...
class B(model.Model):
    属性 = models.OneToOneField(A, on_delete=xxx)
  • 外键类字段选项
  1. on_delete

该参数为必须项

  • models.CASCADE : 级联删除.Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。
  • models.PROTECT : 抛出ProtectedError 以阻止被引用对象的删除;[等同于mysql默认的RESTRICT]
  • models.SET_NULL : 设置ForeignKey null;需要指定null=True
  • models.SET_DEFAULT : 将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。
  • https://docs.djangoproject.com/en/2.2/ref/models/fields/#foreignkey
  1. null
  2. unique
  • 用法示例
  1. 创建作家和作家妻子类
# file : xxxxxxxx/models.py
from django.db import models

class Author(models.Model):
    '''作家模型类'''
    name = models.CharField('作家', max_length=50)

class Wife(models.Model):
    '''作家妻子模型类'''
    name = models.CharField("妻子", max_length=50)
    author = models.OneToOneField(Author, on_delete=models.CASCADE)  # 增加一对一属性 
  1. 创建一对一的数据记录
from .models import *
author1 = Author.objects.create(name='王老师')
wife1 = Wife.objects.create(name='王夫人', author=author1)  # 关联王老师
author2 = Author.objects.create(name='小泽老师')  # 一对一可以没有数据对应的数据 
  1. 数据查询
  • 正向查询,直接通过关联属性查询即可
# 通过 wife 找 author
from .models import Wife
wife = Wife.objects.get(name='王夫人')
print(wife.name, '的老公是', wife.author.name)
  • 反向查询,通过反向关联属性查询
  • 反向关联属性为实例对象.引用类名(小写),如作家的反向引用为作家对象.wife
  • 当反向引用不存在时,则会触发异常
# 通过 author.wife 关联属性 找 wife,如果没有对应的wife则触发异常
author1 = Author.objects.get(name='王老师')
print(author1.name, '的妻子是', author1.wife.name)
author2 = Author.objects.get(name='小泽老师')
try:
    print(author2.name, '的妻子是', author2.wife.name)
except:
    print(author2.name, '还没有妻子')

一对多映射

  • 一对多是表示现实事物间存在的一对多的对应关系。
  • 如:一个学校有多个班级,一个班级有多个学生, 一本图书只能属于一个出版社,一个出版社允许出版多本图书
class A(model.Model):
    ...

class B(model.Model):
    属性 = models.ForeignKey("一"的模型类, on_delete=xx)
  • 有二个出版社对应五本书的情况
  • 清华大学出版社 有书,C++,Java,Python
  • 北京大学出版社 有书,西游记,水浒
  1. 创建模型类
# file: otm/models.py
from django.db import models

class Publisher(models.Model):
    '''出版社【一】'''
    name = models.CharField('名称', max_length=50, unique=True)

class Book(models.Model):
    '''书【多】'''
    title = models.CharField('书名', max_length=50)
    publisher = ForeignKey(Publisher, on_delete=models.CASCADE)
  1. 创建数据
#先创建 '一' ,再创建 '多'
from .models import *
pub1 = Publisher.objects.create(name='清华大学出版社')
Book.objects.create(title='C++', publisher=pub1)
Book.objects.create(title='Java', publisher_id=1)

#高级创建 - 利用 反向属性
pub2 = Publisher.objects.create(name='北京大学出版社')
pub2.book_set.create(title='西游记')
  1. 数据查询
  • 通过 Book 查询 Publisher【正向】
通过 publisher 属性查询即可
book.publisher

abook = Book.objects.get(id=1)
print(abook.title, '的出版社是:', abook.publisher.name)
  • 通过 Publisher 查询 对应的所有的 Book 【反向】
Django会在Publisher中增加一个属性来表示对对应的Book们的查询引用
属性:book_set  等价于 objects

# 通过出版社查询对应的书
pub1 = Publisher.objects.get(name='清华大学出版社')
books = pub1.book_set.all()  # 通过book_set 获取pub1对应的多个Book数据对象
#books = Book.objects.filter(publisher=pub1)  # 也可以采用此方式获取
print("清华大学出版社的书有:")
for book in books:
   print(book.title)

多对多映射

  • 多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,...),每个学校都有不同的学生...

  • 一个作者可以出版多本图书

  • 一本图书可以被多名作者同时编写

class Author(models.Model):
    ...

class Book(models.Model):
    ...
    authors = models.ManyToManyField(Author)
  1. 创建模型类
class Author(models.Model):
    '''作家模型类'''
    name = models.CharField('作家', max_length=50)
    def __str__(self):
        return self.name

class Book(models.Model):
    '''书模型类'''
    title = models.CharField('书名', max_length=50)
    authors = models.ManyToManyField(Author)
    def __str__(self):
        return self.title 
  1. 创建数据
# 方案1 先创建 author 再关联 book
author1 = Author.objects.create(name='吕老师')
author2 = Author.objects.create(name='王老师')
# 吕老师和王老师同时写了一本Python
book11 = author1.book_set.create(title="Python")
author2.book_set.add(book11) 

# 方案2 先创建 book 再关联 author
book = Book.objects.create(title='python1')
#郭小闹和吕老师都参与了 python1 的 创作
author3 = book.authors.create(name='guoxiaonao')
book.authors.add(author1)
  1. 数据查询
  • 通过 Book 查询对应的所有的 Author【正向】
book.authors.all() -> 获取 book 对应的所有的author的信息
book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息
  • 通过 Author 查询对应的所有的Book【反向】
  • Django会生成一个反向属性 book_set 用于表示对对应的book的查询对象相关操作
author.book_set.all()
author.book_set.filter()