一、前言
二、需求分析
三、初始化環(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。
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
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
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)
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)建起來了。 |
|