这是我参与更文挑战的第20天,活动详情查看: 更文挑战
引言
在 Django 模型设计 中我们只设计了一个
BookInfo模型类,内容好单调,接下来我们初步完善一下BMSTes图书管理系统。
模型设计
我们写项目写东西的时候都要养成良好的习惯,不要一来就上手写代码,我们先要进行初步分析和设计,让大脑有整体的概念,需要用到什么技术实现什么效果。这个习惯也不能学的太死,我们要活学活用,学会变通。有时候只是简单的学习一下,或者简单的实现一个小功能。大脑已经可以大概掌握,就无须设计与分析。
初步分析、设计
我们图书管理系统主要实现的是 图书与图书英雄的关联、图书与图书类型的关联管理 ,因此分为图书信息模型、英雄信息模型、图书类型模型,三个模型。对应关系设计如下
一种图书类型,对应多本图书,例如:小说类型的图书,有射雕英雄传、神雕侠侣、倚天屠龙记小说图书等。
一本图书,对应多个英雄,例如:射雕英雄传图书,对应有着郭靖、黄蓉、洪七公等、射雕侠侣则对应杨过、小龙女等。
- 图书类型模型与图书信息模型关联的是1对多的关系
 - 图书信息模型与英雄信息模型关联的是1对多的关系
 
| 实体模型1 | 实体模型2 | 对应关系 | 
|---|---|---|
| 图书类型(BookType) | 图书信息(BookInfo) | 1 : N | 
| 图书信息(BookInfo) | 英雄信息(HeroInfo) | 1 : N | 
具体实现设计
BookType 图书类型模型类
| 类属性 | 数据类型 | 备注 | 
|---|---|---|
| id | IntegerField(整型) | 主键、自增 | 
| type_name | CharField(字符型) | 图书类型 | 
BookInfo 图书模型类
| 类属性 | 数据类型 | 备注 | 
|---|---|---|
| id | IntegerField(整型) | 主键、自增 | 
| book_type | IntegerField(整型)ForeignKey | 
图书类型,外键 | 
| title | CharField(字符型) | 图书名称 | 
| author | CharField(字符型) | 图书作者 | 
| pub_date | CharField(字符型) | 图书出版日期 | 
| isbn | CharField(字符型) | 图书ISBN | 
| book_desc | CharField(字符型) | 图书描述 | 
| book_detail | TextField(文本类型) | 图书详情 | 
| book_price | DecimalField (数值类型) | 图书价格 | 
| book_like_num | IntegerField(整型) | 图书喜欢数 | 
| book_collect_num | IntegerField(整型) | 图书收藏数 | 
HeroInfo 图书英雄模型类
| 类属性 | 数据类型 | 备注 | 
|---|---|---|
| id | IntegerField(整型) | 主键自增 | 
| name | CharField(字符型) | 英雄名称 | 
| gender | CharField(字符型) | 英雄性别 | 
| skill | CharField(字符型) | 英雄技能(武功) | 
| book | InterField(整型)Foreignkey | 
英雄所属图书,外键 | 
Django 模型代码
# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{模型设计模块}
"""
from django.db import models
class BookType(models.Model):
    """图书类别类"""
    type_name = models.CharField(verbose_name=u'图书类型', max_length=20)
    def __str__(self):
        return self.type_name
    class Meta:
        
        db_table = 'BookType'       # 表名称
        verbose_name = '图书类型'   # 表备注
        # 表名复数形式,如果不设置末尾会多一个s
        verbose_name_plural = verbose_name
        
        ordering = ['id']          # 排序字段
class BookInfo(models.Model):
    """图书模型类"""
    title = models.CharField(verbose_name=u'图书名称', max_length=20)
    author = models.CharField(verbose_name=u'图书作者', max_length=20)
    pub_date = models.DateField(verbose_name=u'出版日期')
    book_type = models.ForeignKey(BookType, on_delete=models.CASCADE, verbose_name=u'图书类型')
    isbn = models.CharField(verbose_name='ISBN', max_length=20)
    book_desc = models.CharField(verbose_name=u'图书描述', max_length=128)
    book_detail = models.TextField(verbose_name=u'图书详情')
    book_price = models.DecimalField(verbose_name=u'图书价钱', max_digits=5, decimal_places=2)
    book_like_num = models.IntegerField(verbose_name=u'图书喜欢量')
    book_collect_num = models.IntegerField(verbose_name=u'图书收藏量')
    def __str__(self):
        return self.title
    class Meta:
        db_table = 'BookInfo'
        verbose_name = u'图书信息'
        verbose_name_plural = verbose_name
        ordering = ['id']
class HeroInfo(models.Model):
    """英雄模型类"""
    name = models.CharField(verbose_name=u'英雄姓名', max_length=20)
    # 英雄性别
    gender = models.CharField(verbose_name=u'英雄性别', max_length=3)
    # 英雄技能(武功)
    skill = models.CharField(verbose_name=u'英雄武功', max_length=128)
    # 英雄所属图书
    book = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name=u'图书')
    def __str__(self):
        return self.name
    class Meta:
        db_table = 'HeroInfo'
        verbose_name = u'人物信息'
        verbose_name_plural = verbose_name
        ordering = ['id']
复制代码
设计模型的时候出现了几个之前没用过的字段类型,在这里简单介绍一下。
- TextField: 大文本字段,一般超过4000个字符时使用。
 - IntegerField: 整数。
 - DecimalField(max_digits=None,  decimal_places=None): 十进制浮点数。
- 参数max_digits表示总位数。
 - 参数decimal_places表示小数位数。
 
 
Meta类中的属性
- db_table: 设置创建数据库表的名称,默认的是 
应用名_模型类名 - verbose_name: 设置数据库表的详细信息(表备注)
 - verbose_name_plural: 设置数据表的复数显示形式
 - ordering: 设置数据表的排序字段
 
字段、和Meta类中属性,以后再做详细介绍。
自定义后台管理
模型设计好了,接下来就是在 admin.py 下注册模型了,在注册模型中,我新增了 inlines 、list_per_page 、search_fields属性
- 
inlines: 用于嵌入编辑关联的对象,属性设置在
一对多模型(表)关系中的一中。 - 
admin.TabularInline: 嵌入编辑关联的对象的编辑样式为表格式类
 - 
admin.StackedInline: 嵌入编辑关联的对象的编辑样式为堆放式类
 - 
model: 关联的子对象
 - 
extra: 嵌入编辑子对象的个数
 
- list_per_page: 数据分页,每页的数据个数
 - search_fields: 查询字段
 
# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{后台管理模块}
"""
from django.contrib import admin
from book.models import BookType, BookInfo, HeroInfo
class BookTypeInline(admin.StackedInline):
    model = BookInfo    # 关联的子对象
    extra = 1           # 嵌入编辑子对象的个数
class BookInfoInline(admin.TabularInline):
    model = HeroInfo
    extra = 2
class BookTypeAdmin(admin.ModelAdmin):
    """图书类型模型管理类"""
    # 数据分页,每页10条
    list_per_page = 10
    # 后台显示的属性(字段)
    list_display = ['id', 'type_name']
    # 查询字段
    search_fields = ['type_name']
    # 嵌入编辑关联的对象(表格式)
    inlines = [BookTypeInline]
class BookInfoAdmin(admin.ModelAdmin):
    """图书信息模型管理类"""
    list_per_page = 20
    list_display = [
        'id', 'title', 'author', 'pub_date', 'book_desc', 'book_like_num', 'book_collect_num', 'book_type'
    ]
    search_fields = ['id', 'title', 'author', 'book_desc']
    # 设置图书作者、类型为过滤字段
    list_filter = ['author', 'book_type']
    # 嵌入编辑关联的对象(堆放式)
    inlines = [BookInfoInline]
class HeroInfoAdmin(admin.ModelAdmin):
    """英雄信息模型管理类"""
    list_display = ['id', 'name', 'skill', 'book']
    # 设置图书查询字段
    search_fields = ['name', 'skill', 'book']
    # 设置英雄图书过滤字段
    list_filter = ['book']
# 注册模型类
admin.site.register(BookType, BookTypeAdmin)
admin.site.register(BookInfo, BookInfoAdmin)
admin.site.register(HeroInfo, HeroInfoAdmin)
复制代码
配置MySQL数据库
注册完了模型类,接下来就配置数据库,之前用的是 Django 自带的 sqlite3 数据库,现在我们换成 MySQL 数据库。
首先在 PyCharm 的 Terminal 中输入命令安装 pymysql 驱动
pip install pymysql
复制代码
然后在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',	# MySQL数据库
        # 'NAME': BASE_DIR / 'db.sqlite3',	# sqlite3数据库
        'NAME': 'BMSTest',          # 数据库名称
        'HOST': '127.0.0.1',        # 数据库地址,本机 ip 地址 127.0.0.1
        'PORT': 3306,               # 数据库端口
        'USER': 'root',             # 数据库用户名
        'PASSWORD': '123456',       # 数据库密码
    }
}
复制代码
最后在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置
import pymysql
pymysql.version_info = (1, 4, 13, "final", 0)
pymysql.install_as_MySQLdb()
复制代码
pymysql.version_info = (1, 4, 13, "final", 0)  这行代码
解决 django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.0 or newer is required; you have 0.10.1.  这个错 搜索了下网上的解决办法要么升级要么降级 但是都觉得麻烦于是到处找能不能用几行代码解决的方法 最后成功在stackflow上找到一个办法在 settings.py 同级目录下的 __init__.py 插入这行代码就可以了。
运行服务器
- 创建数据库迁移文件 
python manage.py makemigrations - 执行数据库迁移文件 
python manage.py migrate - 运行服务器 
python manage.py runserver 
如果在运行 python manage.py makemigrations 命令时出现了如下类似的情况
(py_django) D:\Hui\Code\Python\DjangoProject\BMSTest>python manage.py makemigrations
You are trying to add a non-nullable field 'book_type' to bookinfo without a default; we can't do that (the database needs something to populate ex
isting rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option: 
复制代码
说明表结构与之前的表结构发生了变化,之前 BookInfo 的只有 title、author、pub_date,现在的则多了 book_type、isbn、book_desc、book_detail等属性。且这些属性没有 default 默认值,存在 null 值。
解决方案:
- 
1)选择1,则自己提供
default值,输入''空字符即可。 - 
2)选择2,在自己新增的属性中设置
default值、或者允许属性(字段)为空null,例如:book_desc = models.CharField(verbose_name=u'图书描述', max_length=128, null=True) book_detail = models.TextField(verbose_name=u'图书详情', null=True) book_price = models.DecimalField(verbose_name=u'图书价钱', max_digits=5, decimal_places=2, null=True) book_like_num = models.IntegerField(verbose_name=u'图书喜欢量', default=0) book_collect_num = models.IntegerField(verbose_name=u'图书收藏量', default=0) 复制代码新增的属性则为默认值
default、或者空值null。 - 
如果要 切换到其他数据库 时可以在应用下的
migrations目录下删除之前创建的迁移文件然后在创建迁移文件即可。
 
数据库结构

注意:如果切换了数据库,数据不会迁移过来,记得自己手动添加或者导入。
图书类型的分页效果图

图书信息的过滤效果图

嵌入编辑关联的对象(堆放式)
在编辑图书类型的时候,会在下面根据 extra 属性值内嵌入关联的对象(图书信息)的个数

嵌入编辑关联的对象(表格式)

建议:
- 如果关联的模型(表)属性较多,建议使用 堆放式(admin.StackedInline),且不要放置太多,建议1个或者不设置。
 - 如果关联的模型(表)属性较少,放置多些时建议 表格式(admin.TabularInline),少些时任意格式都无伤大雅。
 
这样就不会导致网页,从上到下滑动的太长、或者是从左到右滑动的太长,而不好编辑,不太美观。
公众号
新建文件夹X
大自然用数百亿年创造出我们现实世界,而程序员用几百年创造出一个完全不同的虚拟世界。我们用键盘敲出一砖一瓦,用大脑构建一切。人们把1000视为权威,我们反其道行之,捍卫1024的地位。我们不是键盘侠,我们只是平凡世界中不凡的缔造者 。






















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)