Django+xadmin打造在线教育平台(一)
操作系统:windows 10
Python: 3.7.1
Django: 2.0.6
一、项目创建
浏览原始的前端页面,从页面上进行模块划分,抽象出APP,分析各个APP,初步抽取出APP模型和模型字段,从页面上分析整个项目模板的继承关系。
1、项目模块划分以及各个APP模型抽象
2、创建项目
Django项目我们可以通过用命令的方式创建,也可以直接使用Pycharm创建,为了方便直接使用Pycharm创建
(1)命令行创建Django项目
django-admin startproject GuLiEdu
(2)Pycharm创建
打开Pycharm,创建项目,选择Django
3、创建App
(1)创建App
python manage.py startapp users # 如果在创建项目时候创建,就不用重复创建 python manage.py startapp courses python manage.py startapp orgs python manage.py startapp operations
(2)修改settings文件
①、注册app
将我们刚才创建的app注册到Django中,在INSTALLED_APPS中添加我们创建的app名称
②、数据库配置
DATABASES = { ‘default‘: { ‘ENGINE‘: ‘django.db.backends.mysql‘, ‘NAME‘: ‘guliedu‘, # 需要去数据库创建 ‘USER‘: ‘root‘, ‘PASSWORD‘: ‘123456‘, ‘HOST‘: ‘127.0.0.1‘, ‘PORT‘: 3306 } }
③、国际化设置
LANGUAGE_CODE = ‘zh-hans‘ TIME_ZONE = ‘Asia/Shanghai‘ USE_I18N = True USE_L10N = True USE_TZ = False
④、静态文件路径配置
STATIC_URL = ‘/static/‘ STATICFILES_DIRS = [ os.path.join(BASE_DIR, ‘static‘) ]
⑤设置媒体访问路径
MEDIA_URL = ‘/static/media/‘ MEDIA_ROOT = os.path.join(BASE_DIR, ‘static/media‘)
(3)路由配置
①子路由
分别在四个app中建立urls.py文件,并做简单配置
from django.urls import path app_name = app名称 urlpatterns = [ ]
②总路由
在GuLiEdu目录下的urls中配置分发
from django.urls import path, include urlpatterns = [ path(‘admin/‘, admin.site.urls), path(‘users/‘, include(‘users.urls‘, namespace=‘users‘)), path(‘courses/‘, include(‘courses.urls‘, namespace=‘courses‘)), path(‘orgs/‘, include(‘orgs.urls‘, namespace=‘orgs‘)), path(‘operations/‘, include(‘operations.urls‘, namespace=‘operations‘)), ]
(4)、建立数据模型类
①用户users里面models设计
from django.db import models from django.contrib.auth.models import AbstractUser from datetime import datetime # Create your models here. class UserProfile(AbstractUser): image = models.ImageField(upload_to=‘user/‘, max_length=200, verbose_name=‘用户头像‘, null=True, blank=True) nick_name = models.CharField(max_length=20, verbose_name=‘用户昵称‘, null=True, blank=True) birthday = models.DateTimeField(verbose_name=‘用户生日‘, null=True, blank=True) gender = models.CharField(choices=((‘girl‘, ‘女‘), (‘boy‘, ‘男‘)), max_length=10, verbose_name=‘用户性别‘, default=‘girl‘) address = models.CharField(max_length=200, verbose_name=‘用户地址‘, null=True, blank=True) phone = models.CharField(max_length=11, verbose_name=‘用户手机‘, null=True, blank=True) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.username class Meta: verbose_name = ‘用户信息‘ verbose_name_plural = verbose_name class BannerInfo(models.Model): image = models.ImageField(upload_to=‘banner/‘, verbose_name=‘轮播图片‘, max_length=200) url = models.URLField(default=‘http://www.atguigu.com‘, max_length=200, verbose_name=‘图片链接‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return str(self.image) class Meta: verbose_name = ‘轮播图信息‘ verbose_name_plural = verbose_name class EmailVerify(models.Model): code = models.CharField(max_length=20, verbose_name=‘邮箱验证码‘) email = models.EmailField(max_length=200, verbose_name=‘验证码邮箱‘) send_type = models.IntegerField(choices=((1, ‘register‘), (2, ‘forget‘), (3, ‘change‘)), verbose_name=‘验证码类型‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return str(self.code) class Meta: verbose_name = ‘邮箱验证码‘ verbose_name_plural = verbose_name
users/model
用户表的设计,通过继承扩展Django内部auth模块自带的user表,生成我们自己的用户UserProfile表。注意:当使用继承后,需要在settings配置用户默认模型为自己创建的这个表,要不还是内部的user表settings设置如下:
AUTH_USER_MODEL = ‘users.UserProfile‘
②机构orgs里面models设计
from django.db import models from datetime import datetime # Create your models here. class CityInfo(models.Model): name = models.CharField(max_length=20, verbose_name=‘城市名称‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘城市信息‘ verbose_name_plural = verbose_name class OrgInfo(models.Model): image = models.ImageField(upload_to=‘org/‘, max_length=200, verbose_name=‘机构封面‘) name = models.CharField(max_length=20, verbose_name=‘机构名称‘) course_num = models.IntegerField(default=0, verbose_name=‘课程数‘) study_num = models.IntegerField(default=0, verbose_name=‘学习人数‘) address = models.CharField(max_length=200, verbose_name=‘机构地址‘) desc = models.CharField(max_length=200, verbose_name=‘机构简介‘) detail = models.TextField(verbose_name=‘机构详情‘) love_num = models.IntegerField(default=0, verbose_name=‘收藏数‘) click_num = models.IntegerField(default=0, verbose_name=‘访问量‘) category = models.CharField(choices=((‘pxjg‘, ‘培训机构‘), (‘gx‘, ‘高校‘), (‘gr‘, ‘个人‘)), max_length=10, verbose_name=‘机构类别‘) cityinfo = models.ForeignKey(CityInfo, verbose_name=‘所在城市‘, on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘机构信息‘ verbose_name_plural = verbose_name class TeacherInfo(models.Model): image = models.ImageField(upload_to=‘teacher/‘, max_length=200, verbose_name=‘讲师头像‘) name = models.CharField(max_length=20, verbose_name=‘讲师姓名‘) work_year = models.CharField(default=3, max_length=5, verbose_name=‘工作年限‘) work_position = models.CharField(max_length=20, verbose_name=‘工作职位‘) work_style = models.CharField(max_length=20, verbose_name=‘教学特点‘) work_company = models.ForeignKey(OrgInfo, verbose_name=‘所属机构‘, on_delete=models.CASCADE) age = models.IntegerField(default=30, verbose_name=‘讲师年龄‘) gender = models.CharField(choices=((‘boy‘, ‘男‘), (‘girl‘, ‘女‘)), max_length=10, verbose_name=‘讲师性别‘, default=‘girl‘) love_num = models.IntegerField(default=0, verbose_name=‘收藏数‘) click_num = models.IntegerField(default=0, verbose_name=‘访问量‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘讲师信息‘ verbose_name_plural = verbose_name
orgs/models
③课程courses里面models设计
from django.db import models from datetime import datetime # Create your models here. from orgs.models import OrgInfo, TeacherInfo class CourseInfo(models.Model): image = models.ImageField(upload_to=‘course/‘, max_length=200, verbose_name=‘课程封面‘) name = models.CharField(max_length=20, verbose_name=‘课程名称‘) study_time = models.IntegerField(default=0, verbose_name=‘学习时长‘) study_num = models.IntegerField(default=0, verbose_name=‘学习人数‘) level = models.CharField(choices=((‘cj‘, ‘初级‘), (‘zj‘, ‘中级‘), (‘gj‘, ‘高级‘)), max_length=10, default=‘cj‘, verbose_name=‘课程难度‘) love_num = models.IntegerField(default=0, verbose_name=‘收藏数‘) click_num = models.IntegerField(default=0, verbose_name=‘访问量‘) desc = models.CharField(max_length=200, verbose_name=‘课程简介‘) detail = models.TextField(verbose_name=‘课程详情‘) category = models.CharField(choices=((‘qd‘, ‘前端开发‘), (‘hd‘, ‘后端开发‘)), max_length=10, verbose_name=‘课程类别‘) course_notice = models.CharField(max_length=200, verbose_name=‘课程公告‘) course_need = models.CharField(max_length=100, verbose_name=‘课程须知‘) teacher_tell = models.CharField(max_length=100, verbose_name=‘老师教导‘) orginfo = models.ForeignKey(OrgInfo, verbose_name=‘所属机构‘, on_delete=models.CASCADE) teacherinfo = models.ForeignKey(TeacherInfo, verbose_name=‘所属讲师‘, on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘课程表‘ verbose_name_plural = verbose_name class LessonInfo(models.Model): name = models.CharField(max_length=50, verbose_name=‘章节名称‘) courseinfo = models.ForeignKey(CourseInfo, verbose_name=‘所属课程‘, on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘章节信息‘ verbose_name_plural = verbose_name class VideoInfo(models.Model): name = models.CharField(max_length=50, verbose_name=‘视频名称‘) study_time = models.IntegerField(default=0, verbose_name=‘视频时长‘) url = models.URLField(default=‘http://www.atguigu.com‘, verbose_name=‘视频链接‘, max_length=200) lessoninfo = models.ForeignKey(LessonInfo, verbose_name=‘所属章节‘, on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘视频信息‘ verbose_name_plural = verbose_name class SourceInfo(models.Model): name = models.CharField(max_length=50, verbose_name=‘视频名称‘) down_load = models.FileField(upload_to=‘source/‘, max_length=200, verbose_name=‘下载路径‘) courseinfo = models.ForeignKey(CourseInfo, verbose_name=‘所属课程‘, on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘资源信息‘ verbose_name_plural = verbose_name
courses/models
在settings文件中,添加图片处理器,为了在课程列表中前面加上MEDIA_URL
‘django.template.context_processors.media‘, # 添加图片处理器,为了在课程列表中前面加上MEDIA_URL
④用户操作operations里面models设计
from django.db import models from datetime import datetime from courses.models import CourseInfo from users.models import UserProfile # Create your models here. class UserAsk(models.Model): name = models.CharField(max_length=30, verbose_name=‘姓名‘) phone = models.CharField(max_length=11, verbose_name=‘手机‘) course = models.CharField(max_length=20, verbose_name=‘课程‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.name class Meta: verbose_name = ‘咨询信息‘ verbose_name_plural = verbose_name class UserLove(models.Model): love_man = models.ForeignKey(UserProfile, verbose_name=‘收藏用户‘, on_delete=models.CASCADE) love_id = models.IntegerField(verbose_name=‘收藏ID‘) # 可以是机构,课程,老师 love_type = models.IntegerField(choices=((1, ‘org‘), (2, ‘course‘), (3, ‘teacher‘)), verbose_name=‘收藏类别‘) love_status = models.BooleanField(default=False, verbose_name=‘收藏状态‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.love_man.username class Meta: verbose_name = ‘收藏信息‘ verbose_name_plural = verbose_name class UserCourse(models.Model): study_man = models.ForeignKey(UserProfile, verbose_name=‘学习用户‘, on_delete=models.CASCADE) study_course = models.ForeignKey(CourseInfo, verbose_name=‘学习课程‘, on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.study_man class Meta: unique_together = (‘study_man‘, ‘study_course‘) # 联合唯一 verbose_name = ‘用户学习信息‘ verbose_name_plural = verbose_name class UserComment(models.Model): comment_man = models.ForeignKey(UserProfile, verbose_name=‘评论用户‘, on_delete=models.CASCADE) comment_course = models.ForeignKey(CourseInfo, verbose_name=‘评论课程‘, on_delete=models.CASCADE) comment_content = models.CharField(max_length=300, verbose_name=‘评论内容‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.comment_content class Meta: verbose_name = ‘用户课程信息‘ verbose_name_plural = verbose_name class UserMessage(models.Model): message_man = models.IntegerField(default=0, verbose_name=‘消息用户‘) # 如果id为0,系统消息 message_content = models.CharField(max_length=200, verbose_name=‘消息内容‘) message_status = models.BooleanField(default=False, verbose_name=‘消息状态‘) add_time = models.DateTimeField(default=datetime.now, verbose_name=‘添加时间‘) def __str__(self): return self.message_content class Meta: verbose_name = ‘用户消息‘ verbose_name_plural = verbose_name
operations/models
4、整合4个app到apps
根目录下创建apps包,将四个app分别拖入包中,不要选“Search for references”
如果选择,搜索还是从原始路径去搜索。
在apps上右键Mark
为sourceRoot
。
设置settings文件,为其加上python环境变量。
import os # 代表系统环境 import sys # 代表python环境 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 将我们自己定义的包加入到Python搜寻环境变量当中 sys.path.insert(0, os.path.join(BASE_DIR, ‘Apps‘))
5、迁移数据库
python manage.py makemigrations python manage.py migrate
二、xadmin的使用
1、xadmin的简介
http://sshwsfc.github.io/xadmin/ xadmin的官网
xadmin是一个Django的管理后台实现,使用了更加灵活的架构设计及Bootstrap UI框架, 目的是替换现有的admin,国人开发,有许多新的特性。详情参考上面xadmin官方网站。
2、xadmin的下载和安装(源码包安装)
(1)下载
在xadmin官方网站上我们可以看到xadmin的介绍,并且我们也可以发现xadmin的源码被托管在GitHub上,因此,我们可以去GitHub轻松获取到xadmin源码进行安装。
点击如图所示按钮后,我们可以通过git clone的方式或者直接选择下载zip的方式可以获取到xadmin的源码下载包。
(2)安装
a、 复制xadmin文件夹到我们的项目根目录当中
b、 创建extra_apps放置第三方的app,将xadmin移动到我们这个extra_apps下
c、 将extra_apps mark为root_source
d、 将extra_apps在setting当中配置好搜索路径
sys.path.insert(0, os.path.join(BASE_DIR, ‘extra_apps‘))
e、 依赖包装完之后,再去install当中添加上app
f、将xadmin和crispy_forms添加到我们的installed_apps
g、在总路由urls.py中将我们本来的admin注释掉改为我们xadmin
import xadmin from django.urls import path, include urlpatterns = [ path(‘xadmin/‘, xadmin.site.urls), path(‘users/‘, include(‘users.urls‘, namespace=‘users‘)), path(‘courses/‘, include(‘courses.urls‘, namespace=‘courses‘)), path(‘orgs/‘, include(‘orgs.urls‘, namespace=‘orgs‘)), path(‘operations/‘, include(‘operations.urls‘, namespace=‘operations‘)), ]
h、再次执行迁移同步,目的是为了生成xadmin所依赖的表
i、创建超级管理员,去验证xadmin是否安装成功
python manage.py createsuperuser
(3)、xadmin的注册
在相应的app当中创建adminx.py文件,导入xadmin以及models中的模型,下面以users示例
import xadmin from .models import BannerInfo, EmailVerifyCode class BannerInfoXadmin(object): list_display = [‘image‘, ‘url‘, ‘add_time‘] # 显示 search_fields = [‘image‘, ‘url‘] # 搜索框 list_filter = [‘image‘, ‘url‘] # 过滤器 class EmailVerifyCodeXadmin(object): list_display = [‘code‘, ‘email‘, ‘send_type‘, ‘add_time‘] xadmin.site.register(BannerInfo, BannerInfoXadmin) # 注册 xadmin.site.register(EmailVerifyCode, EmailVerifyCodeXadmin)
如上图所示,左侧显示了轮播图信息以及邮箱验证码两个模型,在轮播图信息中,我们添加了过滤器以及搜索框。
另外三个app方法与users类似。
import xadmin from .models import CityInfo,OrgInfo,TeacherInfo class CityInfoXadmin(object): list_display = [‘name‘, ‘add_time‘] class OrgInfoXadmin(object): list_display = [‘image‘, ‘name‘, ‘course_num‘, ‘study_num‘, ‘love_num‘, ‘click_num‘,‘category‘, ‘cityinfo‘] class TeacherInfoXadmin(object): list_display = [‘image‘, ‘name‘, ‘work_year‘, ‘work_position‘, ‘work_style‘, ‘work_company‘, ‘age‘, ‘gender‘, ‘love_num‘, ‘click_num‘] xadmin.site.register(CityInfo, CityInfoXadmin) xadmin.site.register(OrgInfo, OrgInfoXadmin) xadmin.site.register(TeacherInfo, TeacherInfoXadmin)
orgs/xadmin.py
import xadmin from .models import * class CourseInfoXadmin(object): list_display = [‘image‘,‘name‘,‘study_num‘,‘level‘,‘love_num‘,‘category‘,‘orginfo‘,‘teacherinfo‘] class LessonInfoXadmin(object): list_display = [‘name‘, ‘courseinfo‘, ‘add_time‘] class VideoInfoXadmin(object): list_display = [‘name‘, ‘study_time‘, ‘url‘, ‘lessoninfo‘] class SourceInfoXadmin(object): list_display = [‘name‘, ‘down_load‘, ‘courseinfo‘, ‘add_time‘] xadmin.site.register(CourseInfo,CourseInfoXadmin) xadmin.site.register(LessonInfo,LessonInfoXadmin) xadmin.site.register(VideoInfo,VideoInfoXadmin) xadmin.site.register(SourceInfo,SourceInfoXadmin)
course/adminx.py
import xadmin from .models import * class UserAskXadmin(object): list_display = [‘name‘, ‘phone‘, ‘course‘, ‘add_time‘] class UserLoveXadmin(object): list_display = [‘love_man‘, ‘love_id‘, ‘love_type‘, ‘love_status‘, ‘add_time‘] class UserCourseXadmin(object): list_display = [‘study_man‘, ‘study_course‘, ‘add_time‘] class UserCommentXadmin(object): list_display = [‘comment_man‘, ‘comment_course‘, ‘comment_content‘, ‘add_time‘] class UserMessageXadmin(object): list_display = [‘message_man‘, ‘message_content‘, ‘message_status‘, ‘add_time‘] xadmin.site.register(UserAsk, UserAskXadmin) xadmin.site.register(UserCourse, UserCourseXadmin) xadmin.site.register(UserComment, UserCommentXadmin) xadmin.site.register(UserMessage, UserMessageXadmin)
operations/adminx.py
(4)、将xadmin后台名字改为自己定的名字
方法一:在app当中apps.py文件当中,最下面添加verbose_name=’自定义名字’
方法二: 在app当中的__init__文件当中添加配置
default_app_config = "orgs.apps.OrgsConfig"
说明:可以在installed_apps中安装应用的时候,按照users自动安装的方式去做安装,那么这个__init__文件中的配置也可以省略这里演示将在settings文件中,修改app注册安装方式,然后采用方法一修改字段
INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ‘users.apps.UsersConfig‘, ‘courses.apps.CoursesConfig‘, ‘orgs.apps.OrgsConfig‘, ‘operations.apps.OperationsConfig‘, ‘xadmin‘, ‘crispy_forms‘ ]
(5)、Xadmin后台全局配置
所有的配置都放在users/adminx.py中
①、添加主题
# 配置xadmin主题,注册的时候要用到专用的view去注册 class BaseXadminSetting(object): enable_themes = True # 主题 use_bootswatch = True # 自带主题 xadmin.site.register(views.BaseAdminView, BaseXadminSetting) # 注册主题
②、左侧列表字段“收起”以及标题和底部
class GlobalXadminSetting(object): # 标题和底部公司名称 site_title = ‘Egon人生无限‘ site_footer = ‘小姑娘快过来,让我摸一下屁股‘ menu_style = ‘accordion‘ # 菜单收起 xadmin.site.register(views.CommAdminView, GlobalXadminSetting) # 注册标题和底部公司名称
import xadmin from .models import BannerInfo, EmailVerifyCode from xadmin import views # 配置xadmin主题,注册的时候要用到专用的view去注册 class BaseXadminSetting(object): enable_themes = True # 主题 use_bootswatch = True # 自带主题 class GlobalXadminSetting(object): # 标题和底部公司名称 site_title = ‘Egon人生无限‘ site_footer = ‘小姑娘快过来,让我摸一下屁股‘ menu_style = ‘accordion‘ # 列表菜单收起 class BannerInfoXadmin(object): list_display = [‘image‘, ‘url‘, ‘add_time‘] # 显示 search_fields = [‘image‘, ‘url‘] # 搜索框 list_filter = [‘image‘, ‘url‘] # 过滤器 class EmailVerifyCodeXadmin(object): list_display = [‘code‘, ‘email‘, ‘send_type‘, ‘add_time‘] xadmin.site.register(views.BaseAdminView, BaseXadminSetting) # 注册主题 xadmin.site.register(views.CommAdminView, GlobalXadminSetting) # 注册标题和底部公司名称 xadmin.site.register(BannerInfo, BannerInfoXadmin) xadmin.site.register(EmailVerifyCode, EmailVerifyCodeXadmin)
adminx.py完整代码