1. 程式人生 > >最新Django2.0.1線上教育零基礎到上線教程(四)5-完結

最新Django2.0.1線上教育零基礎到上線教程(四)5-完結

4-5 user modesl.py設計

迴圈引用:

設計app時每個app都有model

mark

如圖:我們在user中定義usercourse記錄使用者學習的課程。會有兩個外來鍵:user和course。
我們就會import Courses.models

如果使用者對課程的評論:會放在 Courses.models當中。評論我們需要儲存相應的使用者。
我們就會import User.models

迴圈import會出錯。a與b相互呼叫,造成等待。

解決迴圈引用: 分層設計

目前已有app:users courses organization

另外一個app高於這些app的層級。operation

.上一層app可以import下層的app。

mark

上節中: 自定義userprofile 覆蓋預設user

user中還需要新增的(前提是這些功能比較獨立):

  • EmailVerifyRecord - 郵箱驗證碼
  • PageBanner - 輪播圖

觀察輪播圖:

  1. 圖片 2. 點選圖片地址 3. 輪播圖序號(控制前後)

mark

users/models.py中新增程式碼:

from datetime import datetime

# 郵箱驗證碼model


class EmailVerifyRecord(models.Model):
    SEND_CHOICES = (
        ("register"
, u"註冊"), ("forget", u"找回密碼") ) code = models.CharField(max_length=20, verbose_name=u"驗證碼") # 未設定null = true blank = true 預設不可為空 email = models.EmailField(max_length=50, verbose_name=u"郵箱") send_type = models.CharField(choices=SEND_CHOICES, max_length=10) # 這裡的now得去掉(),不去掉會根據編譯時間。而不是根據例項化時間。
send_time = models.DateTimeField(default=datetime.now) class Meta: verbose_name = "郵箱驗證碼" verbose_name_plural = verbose_name # 輪播圖model class Banner(models.Model): title = models.CharField(max_length=100, verbose_name=u"標題") image = models.ImageField( upload_to="banner/%Y/%m", verbose_name=u"輪播圖", max_length=100) url = models.URLField(max_length=200, verbose_name=u"訪問地址") # 預設index很大靠後。想要靠前修改index值。 index = models.IntegerField(default=100, verbose_name=u"順序") add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間") class Meta: verbose_name = u"輪播圖" verbose_name_plural = verbose_name

從上往下: 第一塊區域import官方包,第二塊import第三方。(PEP8)

mark

如下圖: 我們一共建立了三個資料表: Structure可以檢視到

mark

與使用者相關的評論啊,點贊啊。學習的課程啊並沒有放進來,因為那些獨立性不高。
容易產生迴圈引用。我們把那些放到operation中。

本小節完成,對應commit:

Usermodel新增郵箱驗證碼,首頁輪播圖。對應4-5

4-6 course models.py編寫

點選 Tools 選單下 Run manage.py Task

startapp courses

course中需要那些表:

  • 課程本身需要一張表

mark

mark

  • 點進去之後點選開始學習。

  • 課程基本資訊需要一張表, 章節表與課程表存在(一個課程對應多個章節)

  • 章節表中:章節的名稱。 章節與視訊(一個章節對應多個視訊)

結構: 課程本身–(一對多)>章節-(一對多)->視訊資訊

資源下載放在課程裡面的。一個課程對應多個資源

共四張表:課程本身–(一對多)>章節-(一對多)->視訊資訊 & 資源表

mark

courses/models.py:

from datetime import datetime

# 課程資訊表
class Course(models.Model):
    DEGREE_CHOICES = (
        ("cj", u"初級"),
        ("zj", u"中級"),
        ("gj", u"高階")
    )
    name = models.CharField(max_length=50, verbose_name=u"課程名")
    desc = models.CharField(max_length=300, verbose_name=u"課程描述")
    # TextField允許我們不輸入長度。可以輸入到無限大。暫時定義為TextFiled,之後更新為富文字
    detail = models.TextField(verbose_name=u"課程詳情")
    degree = models.CharField(choices=DEGREE_CHOICES, max_length=2)
    # 使用分鐘做後臺記錄(儲存最小單位)前臺轉換
    learn_times = models.IntegerField(default=0, verbose_name=u"學習時長(分鐘數)")
    # 儲存學習人數:點選開始學習才算
    students = models.IntegerField(default=0, verbose_name=u"學習人數")
    fav_nums = models.IntegerField(default=0, verbose_name=u"收藏人數")
    image = models.ImageField(
        upload_to="courses/%Y/%m",
        verbose_name=u"封面圖",
        max_length=100)
    # 儲存點選量,點進頁面就算
    click_nums = models.IntegerField(default=0, verbose_name=u"點選數")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"課程"
        verbose_name_plural = verbose_name

下面來編寫章節 & 視訊 & 課程資源:courses/models.py

一對多, 多對一都可以使用django的外來鍵來完成。

# 章節
class Lesson(models.Model):
    # 因為一個課程對應很多章節。所以在章節表中將課程設定為外來鍵。
    # 作為一個欄位來讓我們可以知道這個章節對應那個課程
    course = models.ForeignKey(Course, verbose_name=u"課程")
    name = models.CharField(max_length=100, verbose_name=u"章節名")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"章節"
        verbose_name_plural = verbose_name


# 每章視訊
class Video(models.Model):
    # 因為一個章節對應很多視訊。所以在視訊表中將章節設定為外來鍵。
    # 作為一個欄位來儲存讓我們可以知道這個視訊對應哪個章節.
    lesson = models.ForeignKey(Lesson, verbose_name=u"章節")
    name = models.CharField(max_length=100, verbose_name=u"視訊名")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"視訊"
        verbose_name_plural = verbose_name


# 課程資源
class CourseResource(models.Model):
    # 因為一個課程對應很多資源。所以在課程資源表中將課程設定為外來鍵。
    # 作為一個欄位來讓我們可以知道這個資源對應那個課程
    course = models.ForeignKey(Course, verbose_name=u"課程")
    name = models.CharField(max_length=100, verbose_name=u"名稱")
    # 這裡定義成檔案型別的field,後臺管理系統中會直接有上傳的按鈕。
    # FileField也是一個字串型別,要指定最大長度。
    download = models.FileField(
        upload_to="course/resource/%Y/%m",
        verbose_name=u"資原始檔",
        max_length=100)
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"課程資源"
        verbose_name_plural = verbose_name

通過Structure可以看到我們剛才設計的四張表

mark

本小節完畢, 對應commit:

設計完成課程app中四張資料表: 課程,章節,視訊,資源。對應4-6

4-7 organization modesl.py設計

新建課程機構app:

點選Tools 選單下 Run manage.py Task

startapp organization

課程是屬於機構的, 機構有機構類別,城市等欄位。講師實體。
我要學習的提交表單會與使用者關聯,存放在機構。

mark

mark

其中課程數,學習人數可以動態統計。機構地址,機構經典課程。

機構講師,機構課程可以通過外來鍵獲取到, 不儲存到機構中。

mark

講師大概所需要的欄位如圖所示。

organization/models.py 程式碼如下:

# encoding : utf-8
from datetime import datetime

from django.db import models

# Create your models here.


# 城市字典
class CityDict(models.Model):
    name = models.CharField(max_length=20, verbose_name=u"城市")
    # 城市描述:備用不一定展示出來
    desc = models.CharField(max_length=200, verbose_name=u"描述")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"城市"
        verbose_name_plural = verbose_name


# 課程機構
class CourseOrg(models.Model):
    name = models.CharField(max_length=50, verbose_name=u"機構名稱")
    # 機構描述,後面會替換為富文字展示
    desc = models.TextField(verbose_name=u"機構描述")
    click_nums = models.IntegerField(default=0, verbose_name=u"點選數")
    fav_nums = models.IntegerField(default=0, verbose_name=u"收藏數")
    image = models.ImageField(
        upload_to="org/%Y/%m",
        verbose_name=u"封面圖",
        max_length=100)
    address = models.CharField(max_length=150, verbose_name=u"機構地址")
    # 一個城市可以有很多課程機構,通過將city設定外來鍵,變成課程機構的一個欄位
    # 可以讓我們通過機構找到城市
    city = models.ForeignKey(CityDict, verbose_name=u"所在城市")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"課程機構"
        verbose_name_plural = verbose_name


# 講師
class Teacher(models.Model):
    # 一個機構會有很多老師,所以我們在講師表新增外來鍵並把課程機構名稱儲存下來
    # 可以使我們通過講師找到對應的機構
    org = models.ForeignKey(CourseOrg, verbose_name=u"所屬機構")
    name = models.CharField(max_length=50, verbose_name=u"教師名稱")
    work_years = models.IntegerField(default=0, verbose_name=u"工作年限")
    work_company = models.CharField(max_length=50, verbose_name=u"就職公司")
    work_position = models.CharField(max_length=50, verbose_name=u"公司職位")
    points = models.CharField(max_length=50, verbose_name=u"教學特點")
    click_nums = models.IntegerField(default=0, verbose_name=u"點選數")
    fav_nums = models.IntegerField(default=0, verbose_name=u"收藏數")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"教師"
        verbose_name_plural = verbose_name

mark

可以看到我們一共建立了三張表:分別是城市,課程機構,講師。

本小節對應commit:

課程機構app:城市,機構,講師表書寫完畢。對應4-7

4-8 operation models.py設計

分析需要那些表:

  • 使用者可以提交我要學習的個人需求。
  • 學員的課程評論資訊
  • 收藏:可以收藏公開課, 授課講師, 授課機構, 使用者訊息提醒。
  • 個人中心:我的課程說明使用者和課程之間的學習關係也需要儲存。

mark

新建操作app:

點選Tools 選單下 Run manage.py Task

startapp operation

operation/models.py新增程式碼:

# encoding: utf-8
from datetime import datetime

# 引入我們CourseComments所需要的外來鍵models
from users.models import UserProfile
from courses.models import Course

# 使用者我要學習表單
class UserAsk(models.Model):
    name = models.CharField(max_length=20, verbose_name=u"姓名")
    mobile = models.CharField(max_length=11, verbose_name=u"手機")
    course_name = models.CharField(max_length=50, verbose_name=u"課程名")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"使用者諮詢"
        verbose_name_plural = verbose_name


# 使用者對於課程評論
class CourseComments(models.Model):

    # 會涉及兩個外來鍵: 1. 使用者, 2. 課程。import進來
    course = models.ForeignKey(Course, verbose_name=u"課程")
    user = models.ForeignKey(UserProfile, verbose_name=u"使用者")
    comments = models.CharField(max_length=250, verbose_name=u"評論")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"評論時間")

    class Meta:
        verbose_name = u"課程評論"
        verbose_name_plural = verbose_name


# 使用者對於課程,機構,講師的收藏
class UserFavorite(models.Model):
    # 會涉及四個外來鍵。使用者,課程,機構,講師import
    TYPE_CHOICES = (
        (1, u"課程"),
        (2, u"課程機構"),
        (3, u"講師")
    )

    user = models.ForeignKey(UserProfile, verbose_name=u"使用者")
    # course = models.ForeignKey(Course, verbose_name=u"課程")
    # teacher = models.ForeignKey()
    # org = models.ForeignKey()
    # fav_type =

    # 機智版
    # 直接儲存使用者的id.
    fav_id = models.IntegerField(default=0)
    # 表明收藏的是哪種型別。
    fav_type = models.IntegerField(
        choices=TYPE_CHOICES,
        default=1,
        verbose_name=u"收藏型別")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"評論時間")

    class Meta:
        verbose_name = u"使用者收藏"
        verbose_name_plural = verbose_name


# 使用者訊息表
class UserMessage(models.Model):
        # 因為我們的訊息有兩種:發給全員和發給某一個使用者。
        # 所以如果使用外來鍵,每個訊息會對應要有使用者。很難實現全員訊息。

        # 機智版 為0發給所有使用者,不為0就是發給使用者的id
    user = models.IntegerField(default=0, verbose_name=u"接收使用者")
    message = models.CharField(max_length=500, verbose_name=u"訊息內容")

    # 是否已讀: 布林型別 BooleanField False未讀,True表示已讀
    has_read = models.BooleanField(default=False, verbose_name=u"是否已讀")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"使用者訊息"
        verbose_name_plural = verbose_name


# 使用者課程表
class UserCourse(models.Model):
    # 會涉及兩個外來鍵: 1. 使用者, 2. 課程。import進來
    course = models.ForeignKey(Course, verbose_name=u"課程")
    user = models.ForeignKey(UserProfile, verbose_name=u"使用者")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"新增時間")

    class Meta:
        verbose_name = u"使用者課程"
        verbose_name_plural = verbose_name

至此:我們的五張operation下的資料表models設計完成

mark

setting中配置新增app

mark

本小節對應commit:

operation下的models設計,使用者: 課程&訊息&收藏&評論&我要學習.並在setting中進行了註冊。對應4-8

4-9 資料表生成以及apps目錄建立

學習如何通過剛才設計的models生成資料庫對應的表

點選Tools 選單下 Run manage.py Task:

Python2與Python3不同:

Python2下可能會報一些noASCII錯誤:

只需要在對應你寫了中文的第一行加上:

# encoding: utf-8

Python3(django2.0.1)會報錯:

org = models.ForeignKey(CourseOrg, verbose_name=u"所屬機構")
TypeError: __init__() missing 1 required positional argument: 'on_delete'

這是因為在2.0.1中,外來鍵關係必須指明刪除時的操作。

比如:計程車都歸屬於計程車公司。如果計程車公司倒閉了,那這些汽車該怎麼處理。
必須自己指明: 我覺得可以直接進行級聯刪除。

django提供了:

  • CASCADE
  • PROTECT
  • SET_NULL
  • SET_DEFAULT

等選項。我選擇了CASCADE刪除。

將(dajngo 2.0.1)專案中所有的外來鍵修改為如下面程式碼所示:

也就是添加了on_delete=models.CASCADE使其級聯刪除。

org = models.ForeignKey(CourseOrg, on_delete=models.CASCADE, verbose_name=u"所屬機構")

makemirgration & migrate生成表

makemirgration
migrate

mark

上圖為makemirgration過程中輸出的資訊。可以看到我們做出的改動

mark

此時我們檢視app目錄中migrations資料夾可以看到產生的新檔案。

operation/migrations/0001_initial.py:

可以看到裡面也是Python的語法。他會幫我們生成資料表。
以後每次migrations時都會生成新的initial檔案。這是很重要的變動檔案,不能隨意刪除。

開啟Navicat可以看到django的資料庫中有它預設的django_migrations表

mark

雙擊django_migrations表可以看到我們migration的記錄。

mark

會記錄哪個app下的哪個initial.py已經運行了。

進入Navicat進行成功性驗證:

mark

可以看到我們的表已經生成成功,命名規則為: app名稱 + 我們的類名變成小寫

把我們的四個app放到一個資料夾下。

  • 新建Python的package: apps

mark

  • 把四個app都拖進apps中去。

mark

去掉searchfor的勾選。拖進去之後會報錯,說找不到那些import的模組了。

解決方案:右鍵MarksourceRoot。根目錄下找不到的,會去apps下搜尋。

但是這時候cmd下還是會報錯。

解決方案(圖來源於我的DjangoGetStarted教程):

mark

同理,插入第0是希望它先搜尋我們app下東西:

mark

成功性驗證

mark

mark

可以看到Django已經可以正常run成功了。

第四章總結

  • 我們設計了app

mark

  • 設計了user models.py

mark

  • 迴圈引用

mark

得出我們需要建立一個更高層次的app。分層設計,operation在更高層。

  • Courses models.py

mark

  • organization models.py

mark

  • operation models.py

mark

通過makemigrations 生成表的變動 & migrate
每個app下的migration目錄的用途,和資料庫中django_migration
將所有app放到同一個目錄之下。

本章結束對應commit:

資料表全部生成,migration目錄&表django_migration。將app放到apps目錄。對應4-9.
第四章結束!撒花。