前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Django开发在线教育平台--学习整理(一)

Django开发在线教育平台--学习整理(一)

原创
作者头像
SimonDM
发布2018-05-09 17:19:16
2.9K4
发布2018-05-09 17:19:16
举报

作者: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过来的,应该是视频教程里的图
copy过来的,应该是视频教程里的图
  • 模型设计
自己画的思维导图
自己画的思维导图
  • 模块设计

三、初始化环境

1、新建工程

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

django-admin startproject MxOnline2

2、创建app

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

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

然后,在同级目录下创建一个package,名为apps,用于存放上述四个app。将四个app剪切到apps中,右击apps -> Mark Directory as -> Sources Root。当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、配置目录结构

新建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、数据库配置

# 配置数据库库,使用PostgreSQL
DATABASES = {
    '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 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中时,显示的是当前数据表的名称。
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.name


class 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.name


class 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 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="所属机构", 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.name


class 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 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="标题", 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="评论内容", 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 makemigrations
python manage.py migrate

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

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

五、Admin后台管理系统

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

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):
    # 设置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也能用了,下面就开始把前端页面构建起来了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、需求分析
  • 三、初始化环境
    • 1、新建工程
      • 2、创建app
        • 3、配置目录结构
          • 4、其它配置:
            • 5、数据库配置
            • 四、模型设计Model
            • 五、Admin后台管理系统
            相关产品与服务
            验证码
            腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档