日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Django開發(fā)在線教育平臺

 寧靜致遠(yuǎn)oj1kn5 2019-05-13

作者:SimonDM,轉(zhuǎn)行求職中

寫作目的:無他,但求手熟爾

一、前言

  • 開發(fā)環(huán)境:
    • Python 3.6.4
    • Pycharm 2017.3.3
    • PostgreSQL 10.3
    • pgAdmin4
    • Django 2.0.4
  • git倉庫地址:https://github.com/SimonMQ/MxOnline2
  • 題外話:寫作真的是很麻煩的一件事,要截圖,還要粘代碼。不過跟看著教程寫東西比起來思路倒是清晰了一些,邊學(xué)邊練。勉之!

二、需求分析

  • 項目介紹
    • 系統(tǒng)具有完整的用戶登錄注冊以及找回密碼功能,擁有完整個人中心。
    • 個人中心: 修改頭像,修改密碼,修改郵箱,可以看到我的課程以及我的收藏??梢詣h除收藏,我的消息。
    • 導(dǎo)航欄: 公開課,授課講師,授課機構(gòu),全局搜索。
    • 點擊公開課–> 課程列表,排序-搜索。熱門課程推薦,課程的分頁。
    • 點擊課程–> 課程詳情頁中對課程進(jìn)行收藏,取消收藏。富文本展示課程內(nèi)容。
    • 點擊開始學(xué)習(xí)–> 課程的章節(jié)信息,課程的評論信息。課程資源的下載鏈接。
    • 點擊授課講師–>授課講師列表頁,對講師進(jìn)行人氣排序以及分頁,右邊有講師排行榜。
    • 點擊講師的詳情頁面–> 對講師進(jìn)行收藏和分享,以及講師的全部課程。
    • 導(dǎo)航欄: 授課機構(gòu)有分頁,排序篩選功能。
    • 機構(gòu)列表頁右側(cè)有快速提交我要學(xué)習(xí)的表單。
    • 點擊機構(gòu)–> 左側(cè):機構(gòu)首頁,機構(gòu)課程,機構(gòu)介紹,機構(gòu)講師。
    • 后臺管理系統(tǒng)可以切換主題。左側(cè)每一個功能都有列表顯示, 增刪改查,篩選功能。
    • 課程列表頁可以對不同字段進(jìn)行排序。選擇多條記錄進(jìn)行刪除操作。
    • 課程列表頁:過濾器->選擇字段范圍等,搜索,導(dǎo)出csv,xml,json。
    • 課程新增頁面上傳圖片,富文本的編輯。時間選擇,添加章節(jié),添加課程資源。
    • 日志記錄:記錄后臺人員的操作
  • 系統(tǒng)功能
copy過來的,應(yīng)該是視頻教程里的圖
  • 模型設(shè)計
自己畫的思維導(dǎo)圖
  • 模塊設(shè)計

三、初始化環(huán)境

1、新建工程

首先,打開cmd,cd到存放django項目的文件夾,創(chuàng)建一個新工程(也可以用虛擬環(huán)境virtualenv):

django-admin startproject MxOnline2

2、創(chuàng)建app

創(chuàng)建好工程之后就是配置整個工程的目錄結(jié)構(gòu),先創(chuàng)建四個app:

python manage.py startapp users
python manage.py startapp course
python manage.py startapp organization
python manage.py startapp operation

然后,在同級目錄下創(chuàng)建一個package,名為apps,用于存放上述四個app。將四個app剪切到apps中,右擊apps -> Mark Directory as -> Sources Root。當(dāng)django在根目錄下找不到app時會去apps中去尋找,但此時pycharm知道這么做,而django不知道,所以還要到settings中配置。

import os
import sys

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
# 將四個app放到一個apps包中之后,由于找不到路徑,配置此項。插入第0是希望先搜索apps目錄下的文件
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

之后,在INSTALLED_APPS中注冊四個app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users',
    'course',
    'organization',
    'operation',
]

3、配置目錄結(jié)構(gòu)

新建static文件夾用于存放靜態(tài)文件,css/js/img等;

新建templates文件夾用于存放html文件;

新建media文件夾用于存放后臺上傳的圖片、視頻等文件。

配置settings

static、templates和media雖然創(chuàng)建好了,但是django還無法找到,所以必須在settings中配置。

注意:

STATIC_URL的作用是映射靜態(tài)文件的url,只在templates中引用的時候用到,其用法與MEDIA_URL相同。

STATICFILES_DIRS的作用是由于我們在app之外設(shè)置了其它的static目錄。由于django在運行某個app的html時會默認(rèn)查找這個app下的’static‘目錄,所以在app之外的static需要我們自己配置。這個用法在DEBUG=TRUE時生效,F(xiàn)ALSE時django則不會代管靜態(tài)文件,所以,在部署時會用到STATIC_ROOT。STATICFILES_DIRS的用法與TEMPLATES_DIRS相同。

# 配置靜態(tài)文件路徑
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
# 配置templates路徑
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
# 配置上傳的媒體路徑
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

4、其它配置:

語言和時區(qū)

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

5、數(shù)據(jù)庫配置

# 配置數(shù)據(jù)庫庫,使用PostgreSQL
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mxonline2',
        'USER': 'postgres',
        'PASSWORD': 'MAQING',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}

打開pgAdmin4,新建數(shù)據(jù)庫mxonline2。

四、模型設(shè)計Model

整個項目配置完之后,就要開始著手設(shè)計Model。

  • organization
from django.db import models
from datetime import datetime


# Create your models here.
'''
points:
1、verbose_name的作用是給予對象一個人類可讀的名字,”A human-readable name for the object“。
用于table中某個字段時,在admin后臺會顯示verbose_name,用于Meta中時,顯示的是當(dāng)前數(shù)據(jù)表的名稱。
2、max_length為最大字符長度,由于CharField在數(shù)據(jù)庫中對應(yīng)為varchar,最大長度為255,
所以這里設(shè)置的最大值也不能超過255,否則,用TextField代替。max_length的計算方法:len("字符串")=3。
3、ImageField繼承自FileField,用于上傳文件,其中的upload_to屬性,用于指定上傳文件的目錄,該目錄會在MEDIA_ROOT下自動生成。
如使用upload_to='uploads/%Y/%m/%d/',文件會上傳到MEDIA_ROOT/uploads/2015/01/30中,
/%Y/%m/%d/為strftime()格式化的xxxx年xx月xx日。
4、null=True和blank=True通常一起使用,null代表數(shù)據(jù)庫可以為空,blank代表后臺表單數(shù)據(jù)填寫時可以留白。
5、choices用于選擇框,在使用前應(yīng)該在class中定義一個可迭代對象,[(A, B), (A, B) ...],每個元組中第一個
元素代表實際值,第二個是人類可讀名稱,類似于verbose_name。
'''


class City(models.Model):
    name = models.CharField(verbose_name="城市", max_length=20)
    desc = models.CharField(verbose_name="描述", max_length=255)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

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

    def __str__(self):
        return self.name


class CourseOrg(models.Model):
    ORG_CHOICES = (
        ('pxjg', '培訓(xùn)機構(gòu)'),
        ('gx', '高校'),
        ('gr', '個人'),
    )

    name = models.CharField(verbose_name="機構(gòu)名稱", max_length=20)
    desc = models.TextField(verbose_name="機構(gòu)描述")
    category = models.CharField(verbose_name="機構(gòu)類別", max_length=20, choices=ORG_CHOICES, default='pxjg')
    tag = models.CharField(verbose_name="機構(gòu)標(biāo)簽", max_length=20, default="全國知名")
    image = models.ImageField(verbose_name="封面圖", upload_to='org/%Y/%m')
    address = models.CharField(verbose_name="機構(gòu)地址", max_length=200)
    city = models.ForeignKey(City, verbose_name="所在城市", on_delete=models.CASCADE)
    click_nums = models.IntegerField(verbose_name="點擊數(shù)", default=0)
    learn_nums = models.IntegerField(verbose_name="學(xué)習(xí)人數(shù)", default=0)
    fav_nums = models.IntegerField(verbose_name="收藏數(shù)", default=0)
    course_nums = models.IntegerField(verbose_name="課程數(shù)", default=0)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "課程機構(gòu)"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Teacher(models.Model):
    org = models.ForeignKey(CourseOrg, verbose_name="所屬機構(gòu)", on_delete=models.CASCADE)
    name = models.CharField(verbose_name="姓名", max_length=20)
    age = models.IntegerField(verbose_name="年齡", default=0)
    image = models.ImageField(verbose_name="頭像", upload_to='teacher/%Y/%m', default='', null=True, blank=True)
    work_year = models.IntegerField(verbose_name="工作年限", default=0)
    work_company = models.CharField(verbose_name="就職公司", max_length=50)
    work_position = models.CharField(verbose_name="工作崗位", max_length=50)
    points = models.CharField(verbose_name="教學(xué)特點", max_length=50)
    click_nums = models.IntegerField(verbose_name="點擊數(shù)", default=0)
    fav_nums = models.IntegerField(verbose_name="收藏數(shù)", default=0)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

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

    def __str__(self):
        return self.name
  • course
from django.db import models
from datetime import datetime
from organization.models import CourseOrg, Teacher


# Create your models here.
class Course(models.Model):
    DEGREE_CHOICES = (
        ('cj', '初級'),
        ('zj', '中級'),
        ('gj', '高級'),
    )
    course_org = models.ForeignKey(CourseOrg, verbose_name="所屬機構(gòu)", on_delete=models.CASCADE)
    teacher = models.ForeignKey(Teacher, verbose_name="授課教師", on_delete=models.CASCADE)
    name = models.CharField(verbose_name="名稱", max_length=20)
    desc = models.CharField(verbose_name="課程描述", max_length=255)
    detail = models.TextField(verbose_name="課程詳情")
    image = models.ImageField(verbose_name="封面圖", upload_to='course/%Y/%m')
    degree = models.CharField(verbose_name="難度", choices=DEGREE_CHOICES, max_length=2, default='cj')
    is_banner = models.BooleanField(verbose_name="是否輪播", default=False)
    learn_times = models.IntegerField(verbose_name="課程時長(分鐘數(shù))", default=0)
    click_nums = models.IntegerField(verbose_name="點擊數(shù)", default=0)
    learn_nums = models.IntegerField(verbose_name="學(xué)習(xí)人數(shù)", default=0)
    fav_nums = models.IntegerField(verbose_name="收藏數(shù)", default=0)
    category = models.CharField(verbose_name="分類", max_length=20)
    tag = models.CharField(verbose_name="標(biāo)簽", max_length=20)
    you_need_know = models.CharField(verbose_name="課程須知", max_length=255, default="本課程需要靜心閱讀")
    teacher_tell = models.CharField(verbose_name="老師告訴你", max_length=255, default="好好學(xué)習(xí),天天向上")
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

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

    def __str__(self):
        return self.name


class Lesson(models.Model):
    course = models.ForeignKey(Course, verbose_name="所屬課程", on_delete=models.CASCADE)
    name = models.CharField(verbose_name="章節(jié)名", max_length=20)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "章節(jié)"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '《{0}》課程的章節(jié) >> {1}'.format(self.course, self.name)


class Video(models.Model):
    lesson = models.ForeignKey(Lesson, verbose_name="所屬章節(jié)", on_delete=models.CASCADE)
    name = models.CharField(verbose_name="視頻名", max_length=20)
    # 這里的視頻地址是否可以替換為一個FileField?
    url = models.URLField(verbose_name="視頻地址", max_length=200, default='')
    learn_times = models.IntegerField(verbose_name="視頻時長(分鐘數(shù))", default=0)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "視頻"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '《{0}》章節(jié)的視頻 >> {1}'.format(self.lesson, self.name)


class CourseResource(models.Model):
    course = models.ForeignKey(Course, verbose_name="所屬課程", on_delete=models.CASCADE)
    name = models.CharField(verbose_name="資源名", max_length=20)
    resource = models.FileField(verbose_name="資源文件", upload_to='course/resource/%Y%m')
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

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

    def __str__(self):
        return self.name
  • users
from django.db import models
from datetime import datetime

from django.contrib.auth.models import AbstractUser


# Create your models here.
class UserProfile(AbstractUser):
    GENDER_CHOICES = (
        ('male', '男'),
        ('female', '女'),
    )
    nick_name = models.CharField(verbose_name="昵稱", max_length=20)
    birthday = models.DateField(verbose_name="生日", null=True, blank=True)
    gender = models.CharField(verbose_name="性別", choices=GENDER_CHOICES, max_length=6, default='male')
    address = models.CharField(verbose_name="地址", max_length=100, default='')
    mobile = models.CharField(verbose_name="手機號", max_length=11, null=True, blank=True)
    image = models.ImageField(verbose_name="頭像", upload_to='image/%Y/%m', default='')

    class Meta:
        verbose_name = "用戶信息"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username


class EmailVerifyRecord(models.Model):
    VERIFY_RECORD_CHOICES = (
        ('register', '注冊'),
        ('forget', '找回密碼'),
        ('update_email', '修改郵箱'),
    )
    code = models.CharField(verbose_name="驗證碼", max_length=20)
    email = models.EmailField(verbose_name="郵箱", max_length=100)
    send_type = models.CharField(verbose_name="驗證碼類型", choices=VERIFY_RECORD_CHOICES, max_length=20)
    send_time = models.DateTimeField(verbose_name="", default=datetime.now)

    class Meta:
        verbose_name = "郵箱驗證碼"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '{0}({1})'.format(self.code, self.email)


class Banner(models.Model):
    title = models.CharField(verbose_name="標(biāo)題", max_length=100)
    image = models.ImageField(verbose_name="輪播圖", upload_to='banner/%Y/%m')
    url = models.URLField(verbose_name="訪問地址", max_length=200)
    index = models.IntegerField(verbose_name="順序", default=100)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "輪播圖"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '{0}(位于第{1}位)'.format(self.title, self.index)
  • operation
from django.db import models
from datetime import datetime
from course.models import Course
from users.models import UserProfile


# Create your models here.
class UserAsk(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=20)
    mobile = models.CharField(verbose_name="手機號", max_length=11)
    course_name = models.CharField(verbose_name="課程名", max_length=50)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "用戶咨詢"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用戶:{0} 的手機號:{1}'.format(self.name, self.mobile)


class CourseComment(models.Model):
    course = models.ForeignKey(Course, verbose_name="評論課程", on_delete=models.CASCADE)
    user = models.ForeignKey(UserProfile, verbose_name="評論用戶", on_delete=models.CASCADE)
    comment = models.CharField(verbose_name="評論內(nèi)容", max_length=255)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

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

    def __str__(self):
        return '用戶({0})對于《{1}》的評論'.format(self.user, self.course)


class UserFavorite(models.Model):
    TYPE_CHOICES = (
        (1, '機構(gòu)'),
        (2, '課程'),
        (3, '教師'),
    )
    user = models.ForeignKey(UserProfile, verbose_name="用戶", on_delete=models.CASCADE)
    fav_type = models.IntegerField(verbose_name="收藏類型", choices=TYPE_CHOICES, default=1)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "用戶收藏"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用戶({0})收藏了{(lán)1}'.format(self.user, self.fav_type)


class UserMessage(models.Model):
    # 為0則發(fā)送給所有用戶,否則就是用戶的id
    user = models.IntegerField(verbose_name="用戶", default=0)
    message = models.CharField(verbose_name="消息內(nèi)容", max_length=255)
    has_read = models.BooleanField(verbose_name="是否已讀", default=False)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "用戶消息"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用戶({0})接收了消息:{1}'.format(self.user, self.message)


class UserCourse(models.Model):
    course = models.ForeignKey(Course, verbose_name="課程", on_delete=models.CASCADE)
    user = models.ForeignKey(UserProfile, verbose_name="用戶", on_delete=models.CASCADE)
    add_time = models.DateTimeField(verbose_name="添加時間", default=datetime.now)

    class Meta:
        verbose_name = "用戶課程"
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用戶({0})學(xué)習(xí)了《{1}》'.format(self.user, self.course)

這里需要注意的是,django為我們提供了User表,功能包括:id、password、is_superuser、is_active、email等。如果我們需要擴展可以復(fù)寫AbsractUser模型,之后,需要在settings中告訴django我們新的用戶模型:

# 由于復(fù)寫了user模型,我們需要重載AUTH_USER_MODEL參數(shù),導(dǎo)入我們復(fù)寫后的模型
AUTH_USER_MODEL = 'users.UserProfile'

然后運行migrate,將寫好的數(shù)據(jù)遷移到數(shù)據(jù)庫中:

python manage.py makemigrations
python manage.py migrate

這時,打開pgAdmin4,就會發(fā)現(xiàn)創(chuàng)建了24張table,其中除了我們剛剛創(chuàng)建的15張之外,還有系統(tǒng)自動生成的,包括遷移記錄,會話等等。

另外,右擊某張表,選擇View/All Rows可以查看當(dāng)前表的字段和數(shù)據(jù)信息。

五、Admin后臺管理系統(tǒng)

使用django自帶的Admin之前先創(chuàng)建一個超級管理員賬戶:

E:\DjangoProjects\MxOnline2>python manage.py createsuperuse
Username: simondm
Email address: 352830021@qq.com
Password:
Password (again):
Superuser created successfully.

然后,在每個app下的admin.py中注冊并定制admin后臺模型:

from django.contrib import admin
from .models import Course, Lesson, Video, CourseResource


# Register your models here.
# 在admin后臺注冊模型,并且定制后臺
class CourseAdmin(admin.ModelAdmin):
    # 設(shè)置fieldsets 控制管理“添加”和 “更改” 頁面的布局,順便可以給這些字段排序
    fieldsets = (
        (None, {
            'fields': ('name', 'desc', 'tag', 'is_banner', ('course_org', 'teacher'), 'degree', 'learn_times', ('click_nums', 'learn_nums', 'fav_nums'), 'category')
        }),
        ('其它選項', {
            'fields': ('detail', 'image', 'you_need_know', 'teacher_tell', 'add_time')
        }),
    )

    # 指定修改頁面上顯示的字段,如果不指定,則只顯示__str__()指定的那一列。
    list_display = ('name', 'desc', 'course_org', 'teacher', 'is_banner', 'colored_degree', 'learn_times', 'learn_nums')
    search_fields = ('name', 'desc', 'detail', 'degree', 'learn_nums')
    list_filter = ('name', 'desc', 'detail', 'degree', 'learn_times', 'learn_nums')


class LessonAdmin(admin.ModelAdmin):
    list_display = ('course', 'name', 'add_time')
    search_fields = ('course', 'name')
    # 由于course是一個外鍵,所以過濾的時候根據(jù)課程名稱過濾,即course.name
    list_filter = ('course__name', 'name', 'add_time')


class VideoAdmin(admin.ModelAdmin):
    list_display = ('lesson', 'name', 'add_time')
    search_fields = ('lesson', 'name')
    list_filter = ('lesson', 'name', 'add_time')


class CourseResourceAdmin(admin.ModelAdmin):
    list_display = ('course', 'name', 'resource', 'add_time')
    search_fields = ('course', 'name', 'resource')
    list_filter = ('course__name', 'name', 'resource', 'add_time')


# models與admin關(guān)聯(lián)注冊
admin.site.register(Course, CourseAdmin)
admin.site.register(Lesson, LessonAdmin)
admin.site.register(Video, VideoAdmin)
admin.site.register(CourseResource, CourseResourceAdmin)

常用幾個功能:

list_display:設(shè)置修改頁面顯示哪些字段

search_fields:設(shè)置搜索框搜索數(shù)據(jù)

list_filter:設(shè)置右側(cè)篩選欄

fieldsets:設(shè)置頁面布局

設(shè)置好后的頁面:

后臺首頁:

課程Table頁:

修改課程詳情頁:

這里只是實現(xiàn)簡單的功能,django的admin功能非常強大,待后續(xù)完善。

基本的結(jié)構(gòu)搭建好了,模型有了,admin也能用了,下面就開始把前端頁面構(gòu)建起來了。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多