打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Django开发在线教育平台

作者:SimonDM,转行求职中

写作目的:无他,但求手熟尔

一、前言

  • 开发环境:
    • Python 3.6.4
    • Pycharm 2017.3.3
    • PostgreSQL 10.3
    • pgAdmin4
    • Django 2.0.4
  • git仓库地址:https://github.com/SimonMQ/MxOnline2
  • 题外话:写作真的是很麻烦的一件事,要截图,还要粘代码。不过跟看着教程写东西比起来思路倒是清晰了一些,边学边练。勉之!

二、需求分析

  • 项目介绍
    • 系统具有完整的用户登录注册以及找回密码功能,拥有完整个人中心。
    • 个人中心: 修改头像,修改密码,修改邮箱,可以看到我的课程以及我的收藏。可以删除收藏,我的消息。
    • 导航栏: 公开课,授课讲师,授课机构,全局搜索。
    • 点击公开课–> 课程列表,排序-搜索。热门课程推荐,课程的分页。
    • 点击课程–> 课程详情页中对课程进行收藏,取消收藏。富文本展示课程内容。
    • 点击开始学习–> 课程的章节信息,课程的评论信息。课程资源的下载链接。
    • 点击授课讲师–>授课讲师列表页,对讲师进行人气排序以及分页,右边有讲师排行榜。
    • 点击讲师的详情页面–> 对讲师进行收藏和分享,以及讲师的全部课程。
    • 导航栏: 授课机构有分页,排序筛选功能。
    • 机构列表页右侧有快速提交我要学习的表单。
    • 点击机构–> 左侧:机构首页,机构课程,机构介绍,机构讲师。
    • 后台管理系统可以切换主题。左侧每一个功能都有列表显示, 增删改查,筛选功能。
    • 课程列表页可以对不同字段进行排序。选择多条记录进行删除操作。
    • 课程列表页:过滤器->选择字段范围等,搜索,导出csv,xml,json。
    • 课程新增页面上传图片,富文本的编辑。时间选择,添加章节,添加课程资源。
    • 日志记录:记录后台人员的操作
  • 系统功能
copy过来的,应该是视频教程里的图
  • 模型设计
自己画的思维导图
  • 模块设计

三、初始化环境

1、新建工程

首先,打开cmd,cd到存放django项目的文件夹,创建一个新工程(也可以用虚拟环境virtualenv):

django-admin startproject MxOnline2

2、创建app

创建好工程之后就是配置整个工程的目录结构,先创建四个app:

python manage.py startapp userspython manage.py startapp coursepython manage.py startapp organizationpython manage.py startapp operation

然后,在同级目录下创建一个package,名为apps,用于存放上述四个app。将四个app剪切到apps中,右击apps -> Mark Directory as -> Sources Root。当django在根目录下找不到app时会去apps中去寻找,但此时pycharm知道这么做,而django不知道,所以还要到settings中配置。

import osimport 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、配置目录结构

新建static文件夹用于存放静态文件,css/js/img等;

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

新建media文件夹用于存放后台上传的图片、视频等文件。

配置settings

static、templates和media虽然创建好了,但是django还无法找到,所以必须在settings中配置。

注意:

STATIC_URL的作用是映射静态文件的url,只在templates中引用的时候用到,其用法与MEDIA_URL相同。

STATICFILES_DIRS的作用是由于我们在app之外设置了其它的static目录。由于django在运行某个app的html时会默认查找这个app下的’static‘目录,所以在app之外的static需要我们自己配置。这个用法在DEBUG=TRUE时生效,FALSE时django则不会代管静态文件,所以,在部署时会用到STATIC_ROOT。STATICFILES_DIRS的用法与TEMPLATES_DIRS相同。

# 配置静态文件路径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、其它配置:

语言和时区

LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'

5、数据库配置

# 配置数据库库,使用PostgreSQLDATABASES = {    'default': {        'ENGINE': 'django.db.backends.postgresql',        'NAME': 'mxonline2',        'USER': 'postgres',        'PASSWORD': 'MAQING',        'HOST': '127.0.0.1',        'PORT': '5432',    }}

打开pgAdmin4,新建数据库mxonline2。

四、模型设计Model

整个项目配置完之后,就要开始着手设计Model。

  • organization
from django.db import modelsfrom datetime import datetime# Create your models here.'''points:1、verbose_name的作用是给予对象一个人类可读的名字,”A human-readable name for the object“。用于table中某个字段时,在admin后台会显示verbose_name,用于Meta中时,显示的是当前数据表的名称。2、max_length为最大字符长度,由于CharField在数据库中对应为varchar,最大长度为255,所以这里设置的最大值也不能超过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代表数据库可以为空,blank代表后台表单数据填写时可以留白。5、choices用于选择框,在使用前应该在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.nameclass CourseOrg(models.Model):    ORG_CHOICES = (        ('pxjg', '培训机构'),        ('gx', '高校'),        ('gr', '个人'),    )    name = models.CharField(verbose_name="机构名称", max_length=20)    desc = models.TextField(verbose_name="机构描述")    category = models.CharField(verbose_name="机构类别", max_length=20, choices=ORG_CHOICES, default='pxjg')    tag = models.CharField(verbose_name="机构标签", max_length=20, default="全国知名")    image = models.ImageField(verbose_name="封面图", upload_to='org/%Y/%m')    address = models.CharField(verbose_name="机构地址", max_length=200)    city = models.ForeignKey(City, verbose_name="所在城市", on_delete=models.CASCADE)    click_nums = models.IntegerField(verbose_name="点击数", default=0)    learn_nums = models.IntegerField(verbose_name="学习人数", default=0)    fav_nums = models.IntegerField(verbose_name="收藏数", default=0)    course_nums = models.IntegerField(verbose_name="课程数", 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.nameclass Teacher(models.Model):    org = models.ForeignKey(CourseOrg, verbose_name="所属机构", 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="教学特点", max_length=50)    click_nums = models.IntegerField(verbose_name="点击数", default=0)    fav_nums = models.IntegerField(verbose_name="收藏数", 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 modelsfrom datetime import datetimefrom 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="所属机构", 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="课程时长(分钟数)", default=0)    click_nums = models.IntegerField(verbose_name="点击数", default=0)    learn_nums = models.IntegerField(verbose_name="学习人数", default=0)    fav_nums = models.IntegerField(verbose_name="收藏数", default=0)    category = models.CharField(verbose_name="分类", max_length=20)    tag = models.CharField(verbose_name="标签", max_length=20)    you_need_know = models.CharField(verbose_name="课程须知", max_length=255, default="本课程需要静心阅读")    teacher_tell = models.CharField(verbose_name="老师告诉你", max_length=255, default="好好学习,天天向上")    add_time = models.DateTimeField(verbose_name="添加时间", default=datetime.now)    class Meta:        verbose_name = "课程"        verbose_name_plural = verbose_name    def __str__(self):        return self.nameclass Lesson(models.Model):    course = models.ForeignKey(Course, verbose_name="所属课程", on_delete=models.CASCADE)    name = models.CharField(verbose_name="章节名", max_length=20)    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.course, self.name)class Video(models.Model):    lesson = models.ForeignKey(Lesson, verbose_name="所属章节", 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="视频时长(分钟数)", 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}》章节的视频 >> {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 modelsfrom datetime import datetimefrom 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.usernameclass 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="标题", 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 modelsfrom datetime import datetimefrom course.models import Coursefrom 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="评论内容", 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, '机构'),        (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})收藏了{1}'.format(self.user, self.fav_type)class UserMessage(models.Model):    # 为0则发送给所有用户,否则就是用户的id    user = models.IntegerField(verbose_name="用户", default=0)    message = models.CharField(verbose_name="消息内容", 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})学习了《{1}》'.format(self.user, self.course)

这里需要注意的是,django为我们提供了User表,功能包括:id、password、is_superuser、is_active、email等。如果我们需要扩展可以复写AbsractUser模型,之后,需要在settings中告诉django我们新的用户模型:

# 由于复写了user模型,我们需要重载AUTH_USER_MODEL参数,导入我们复写后的模型AUTH_USER_MODEL = 'users.UserProfile'

然后运行migrate,将写好的数据迁移到数据库中:

python manage.py makemigrationspython manage.py migrate

这时,打开pgAdmin4,就会发现创建了24张table,其中除了我们刚刚创建的15张之外,还有系统自动生成的,包括迁移记录,会话等等。

另外,右击某张表,选择View/All Rows可以查看当前表的字段和数据信息。

五、Admin后台管理系统

使用django自带的Admin之前先创建一个超级管理员账户:

E:\DjangoProjects\MxOnline2>python manage.py createsuperuseUsername: simondmEmail address: 352830021@qq.comPassword:Password (again):Superuser created successfully.

然后,在每个app下的admin.py中注册并定制admin后台模型:

from django.contrib import adminfrom .models import Course, Lesson, Video, CourseResource# Register your models here.# 在admin后台注册模型,并且定制后台class CourseAdmin(admin.ModelAdmin):    # 设置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是一个外键,所以过滤的时候根据课程名称过滤,即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关联注册admin.site.register(Course, CourseAdmin)admin.site.register(Lesson, LessonAdmin)admin.site.register(Video, VideoAdmin)admin.site.register(CourseResource, CourseResourceAdmin)

常用几个功能:

list_display:设置修改页面显示哪些字段

search_fields:设置搜索框搜索数据

list_filter:设置右侧筛选栏

fieldsets:设置页面布局

设置好后的页面:

后台首页:

课程Table页:

修改课程详情页:

这里只是实现简单的功能,django的admin功能非常强大,待后续完善。

基本的结构搭建好了,模型有了,admin也能用了,下面就开始把前端页面构建起来了。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
django---admin添加应用
python测试开发django-31.admin后台一对多关系
django
Django模型层Meta内部类详解
xadmin与django
Django blog项目《十四》:视频播放模块
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服