Django教程 —— 初步完善圖書管理系統

Clever_Hui發表於2020-10-25

引言

Django模型設計 中我們只設計了一個BookInfo模型類,內容好單調,接下來我們初步完善一下BMSTes圖書管理系統。


模型設計

我們寫專案寫東西的時候都要養成良好的習慣,不要一來就上手寫程式碼,我們先要進行初步分析和設計,讓大腦有整體的概念,需要用到什麼技術實現什麼效果。這個習慣也不能學的太死,我們要活學活用,學會變通。有時候只是簡單的學習一下,或者簡單的實現一個小功能。大腦已經可以大概掌握,就無須設計與分析。


初步分析、設計

我們圖書管理系統主要實現的是 圖書與圖書英雄的關聯、圖書與圖書型別的關聯管理 ,因此分為圖書資訊模型、英雄資訊模型、圖書型別模型,三個模型。對應關係設計如下

一種圖書型別,對應多本圖書,例如:小說型別的圖書,有射鵰英雄傳、神鵰俠侶、倚天屠龍記小說圖書等。

一本圖書,對應多個英雄,例如:射鵰英雄傳圖書,對應有著郭靖、黃蓉、洪七公等、射鵰俠侶則對應楊過、小龍女等。

  • 圖書型別模型與圖書資訊模型關聯的是1對多的關係
  • 圖書資訊模型與英雄資訊模型關聯的是1對多的關係
實體模型1實體模型2對應關係
圖書型別(BookType)圖書資訊(BookInfo)1 : N
圖書資訊(BookInfo)英雄資訊(HeroInfo)1 : N

具體實現設計

BookType圖書型別模型類

類屬性資料型別備註
idIntegerField(整型)主鍵、自增
type_nameCharField(字元型)圖書型別

BookInfo圖書模型類

類屬性資料型別備註
idIntegerField(整型)主鍵、自增
book_typeIntegerField(整型)ForeignKey圖書型別,外來鍵
titleCharField(字元型)圖書名稱
authorCharField(字元型)圖書作者
pub_dateCharField(字元型)圖書出版日期
isbnCharField(字元型)圖書ISBN
book_descCharField(字元型)圖書描述
book_detailTextField(文字型別)圖書詳情
book_priceDecimalField (數值型別)圖書價格
book_like_numIntegerField(整型)圖書喜歡數
book_collect_numIntegerField(整型)圖書收藏數

HeroInfo圖書英雄模型類

類屬性資料型別備註
idIntegerField(整型)主鍵自增
nameCharField(字元型)英雄名稱
genderCharField(字元型)英雄性別
skillCharField(字元型)英雄技能(武功)
bookInterField(整型)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 下注冊模型了,在註冊模型中,我新增了 inlineslist_per_pagesearch_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 資料庫。

首先在 PyCharmTerminal 中輸入命令安裝 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 的只有 titleauthorpub_date,現在的則多了 book_typeisbnbook_descbook_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 目錄下刪除之前建立的遷移檔案然後在建立遷移檔案即可。

    Django 資料庫遷移檔案目錄


資料庫結構

BMSTest 資料庫結構


注意:如果切換了資料庫,資料不會遷移過來,記得自己手動新增或者匯入。


圖書型別的分頁效果圖

圖書型別的分頁效果


圖書資訊的過濾效果圖

圖書資訊的過濾屬性效果圖


嵌入編輯關聯的物件(堆放式)

在編輯圖書型別的時候,會在下面根據 extra 屬性值內嵌入關聯的物件(圖書資訊)的個數

嵌入編輯子物件(堆放式)


嵌入編輯關聯的物件(表格式)

嵌入編輯關聯的物件(表格式)


建議:

  • 如果關聯的模型(表)屬性較多,建議使用 堆放式(admin.StackedInline),且不要放置太多,建議1個或者不設定。
  • 如果關聯的模型(表)屬性較少,放置多些時建議 表格式(admin.TabularInline),少些時任意格式都無傷大雅。

這樣就不會導致網頁,從上到下滑動的太長、或者是從左到右滑動的太長,而不好編輯,不太美觀。


公眾號

新建資料夾X

大自然用數百億年創造出我們現實世界,而程式設計師用幾百年創造出一個完全不同的虛擬世界。我們用鍵盤敲出一磚一瓦,用大腦構建一切。人們把1000視為權威,我們反其道行之,捍衛1024的地位。我們不是鍵盤俠,我們只是平凡世界中不凡的締造者 。

相關文章