您现在的位置是: 网站首页 >Django >Django2.0.8+xadmin2实现在线学习网站 Django

【Django在线教育平台】02.创建该项目用到的数据库模型类

admin2019年6月4日 13:31 Django | Html | JQuery 1714人已围观

Django2.0.8+xadmin2实现在线学习网站简介 Django2.0.8+xadmin2实现在线学习网站,课程、讲师、机构、用户收藏功能。GitHub地址:https://github.com/xyliurui/OnlineLearningPlatform ;Django版本:2.0.8

# 模型设计 1. users-用户管理 1. course-课程管理 1. organization-机构和教师管理 1. operation-用户操作管理 ## 用户应用users 点击Tools 菜单下 Run manage.py Task ```python manage.py@DjangoOnlineLearningPlatform > startapp users ``` ### 用户models 系统自动生成的user表如下: * id: 主键, password 密码, last_login Django自动记录用户最后登录时间,。 * is_superuser 表明用户是否是超级用户(后台管理会用到)。 * username 用户名字段不要随便改动, email 邮箱, * is_staff 表示是否是员工(后台管理会用到)。 * is_active 用户是否是激活状态, date_joined 注册时间。 我们需要扩展我们自己的需求字段,例如昵称,生日,性别等。 既要保留原有字段,邮箱添加新的字段,可以使用`AbstractUser`,点击进去就可以看到User原有的字段 编辑users/models.py,添加代码 ```python from django.db import models from django.contrib.auth.models import AbstractUser class UserProfile(AbstractUser): # 自定义的性别选择规则 GENDER_CHOICES = ( ('male', '男'), ('female', '女') ) nick_name = models.CharField(max_length=50, default='', verbose_name='昵称') birthday = models.DateField(null=True, blank=True, verbose_name='生日') gender = models.CharField(max_length=10, choices=GENDER_CHOICES, default='male', verbose_name='性别') address = models.CharField(max_length=100, default='', verbose_name='地址') mobile = models.CharField(max_length=11, null=True, blank=True, verbose_name='电话') image = models.ImageField(upload_to='image/%Y/%m', default='image/default.png', max_length=100, blank=True, null=True, verbose_name='头像') # Meta信息,即后台栏目名 class Meta: verbose_name_plural = verbose_name = '用户信息' def __str__(self): return self.username ``` 点进`AbstractUser`可以看到这个models里面就有我们默认表的那些字段。 因为Image字段需要用到pillow所以需要安装该库 ``` (Venv_learning_platform) D:\Apps\Python>pip install pillow -i https://pypi.douban.com/simple ``` 注意:CharField必须有max_length, Imagefield实际也是charfield所以也要有max_length ### 注册users应用 修改settings.py文件,添加users应用 ```python INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'users', ] ``` ### 重载AUTH_USER_MODEL 修改settings.py文件,添加以下代码 ```python # 此处重载是为了使我们的UserProfile生效,相当于使用UserProfile替换User表使用 AUTH_USER_MODEL = "users.UserProfile" ``` ### 同步users数据库 点击Tools 菜单下 Run manage.py Task ```python manage.py@DjangoOnlineLearningPlatform > makemigrations users manage.py@DjangoOnlineLearningPlatform > migrate users ``` ### 循环引用知识 设计app时每个app都有model ![BLOG_20190604_133351_48](/media/blog/images/2019/06/BLOG_20190604_133351_48.png "博客图集BLOG_20190604_133351_48.png") 如图:我们在user中定义usercourse记录用户学习的课程。会有两个外键:user和course。 我们就会`import Courses.models` 如果用户对课程的评论:会放在 Courses.models当中。评论我们需要保存相应的用户。 我们就会`import User.models` 循环`import`会出错。a与b相互调用,造成等待。 **解决循环引用: 分层设计** 目前已有app:`users`、`courses`、`organization` 另外一个app高于这些app的层级。`operation.上一层app`可以import下层的app。 ![BLOG_20190604_133310_77](/media/blog/images/2019/06/BLOG_20190604_133310_77.png "博客图集BLOG_20190604_133310_77.png") ### 邮箱验证码和轮播图models user中还需要添加的(前提是这些功能比较独立): * EmailVerifyRecord - 邮箱验证码 * PageBanner - 轮播图 ```python # 第一块区域import官方包 from datetime import datetime # 第二块区域import第三方包 from django.db import models from django.contrib.auth.models import AbstractUser # 第三块区域import自己定义的 class EmailVerifyRecord(models.Model): SEND_CHOICES = ( ("register", "注册"), ("forget", "找回密码") ) code = models.CharField(max_length=20, verbose_name='验证码') email = models.EmailField(max_length=50, verbose_name='邮箱') send_type = models.CharField(choices=SEND_CHOICES, default='register', max_length=10, verbose_name='发送类型') # 这里的now得去掉(), 不去掉会根据编译时间。而不是根据实例化时间 send_time = models.DateTimeField(default=datetime.now, verbose_name='发送时间') class Meta: verbose_name_plural = verbose_name = '邮箱验证码' def __str__(self): return '{}({})'.format(self.code, self.email) # 1、图片 2. 点击图片地址 3. 轮播图序号(控制前后) class Banner(models.Model): title = models.CharField(max_length=100, verbose_name='标题') image = models.ImageField(upload_to='banner/%Y/%m', max_length=100, blank=True, null=True, verbose_name='轮播图') url = models.URLField(max_length=200, verbose_name='访问地址') # 默认index很大靠后。想要靠前修改index值。 index = models.IntegerField(default=100, verbose_name='顺序') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '轮播图' def __str__(self): return self.title ``` ### 同步users数据库 ```python manage.py@DjangoOnlineLearningPlatform > makemigrations users manage.py@DjangoOnlineLearningPlatform > migrate users ``` 与用户相关的评论啊,点赞啊。学习的课程啊并没有放进来,因为那些独立性不高。 容易产生循环引用。我们把那些放到operation中。 ## 课程应用courses 点击 Tools 菜单下 Run manage.py Task ```python manage.py@DjangoOnlineLearningPlatform > startapp courses ``` course中需要那些表: * 课程本身需要一张表 * 点进去之后点击开始学习 * 课程基本信息需要一张表,章节表与课程表存在(一个课程对应多个章节) * 章节表中:章节的名称。 章节与视频(一个章节对应多个视频) 课程总体结构: 课程本身---(一对多)--->章节---(一对多)--->视频信息 资源下载放在课程里面的。一个课程对应多个资源 共四张表: 1. 课程本身---(一对多)--->章节----(一对多)---->视频信息 2. 课程本身---(一对多)---> 资源表 * Course - 课程基本信息 * Lesson - 章节信息 * Video - 视频 * CourseResource - 课程资源 ### 课程信息models courses.models.py ```python from django.db import models from datetime import datetime # 课程信息表 class Course(models.Model): DEGREE_CHOICES = ( ("cj", "初级"), ("zj", "中级"), ("gj", "高级") ) name = models.CharField(max_length=50, verbose_name='课程名') desc = models.CharField(max_length=300, verbose_name='课程描述') # 后面会改为富文本 detail = models.TextField(verbose_name='课程详情') degree = models.CharField(max_length=3, choices=DEGREE_CHOICES, verbose_name='课程难度') learn_times = models.IntegerField(default=0, verbose_name='学习时长(分钟数)') # 点击开始学习后记录学习人数 students = models.IntegerField(default=0, verbose_name='学习人数') fav_nums = models.IntegerField(default=0, verbose_name='收藏人数') image = models.ImageField(upload_to='course/%Y/%m', max_length=100, blank=True, null=True, verbose_name='封面图') # 点击到课程信息界面即需要记录点击数 click_nums = models.IntegerField(default=0, verbose_name='点击数') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name = verbose_name_plural = '课程' def __str__(self): return self.name ``` ### 课程其他资源models 一对多, 多对一都可以使用django的外键来完成。 ```python # 课程章节 class Lesson(models.Model): # 一个课程下有多个章节,需要用到一对多的关系,使用外键完成 course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='课程') name = models.CharField(max_length=100, verbose_name='章节名') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '章节' def __str__(self): return '课程 ' + self.course.name + '的章节:' + self.name # 课程视频 class Video(models.Model): lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE, verbose_name='章节') name = models.CharField(max_length=100, verbose_name='视频名') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '视频' def __str__(self): return '章节 ' + self.lesson.name + '的视频:' + self.name # 课程资源 class CourseResource(models.Model): course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='课程') name = models.CharField(max_length=100, verbose_name='名称') # 下载的是文件,需要用到文件下载FileField,在后台管理中会自动生成文件上传的按钮 download = models.FileField(upload_to='course/resource/%Y/%m', max_length=100, verbose_name='资源文件') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '课程资源' def __str__(self): return '课程 ' + self.course.name + '的资源:' + self.name ``` ### 同步courses数据库 settings.py添加courses应用 ```python INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'users', 'courses', ] ``` 执行同步 ```python manage.py@DjangoOnlineLearningPlatform > makemigrations courses manage.py@DjangoOnlineLearningPlatform > migrate courses ``` ## 组织机构organization 点击Tools 菜单下 Run manage.py Task ```python manage.py@DjangoOnlineLearningPlatform > startapp organization ``` 课程是属于机构的, 机构有机构类别,城市等字段。讲师实体。 我要学习的提交表单会与用户关联,存放在机构。 * CourseOrg - 课程机构基本信息 * Teacher - 教师基本信息 * CityDict - 城市信息 ### 课程机构models 其中课程数,学习人数可以动态统计。机构地址,机构经典课程。 organization/models.py ```python from django.db import models from datetime import datetime # 城市信息,用户课程机构所在城市选择 class CityDict(models.Model): name = models.CharField(max_length=20, verbose_name='城市') desc = models.TextField(verbose_name='描述') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural= verbose_name = '城市' def __str__(self): return self.name # 课程机构信息 class CourseOrg(models.Model): name = models.CharField(max_length=50, verbose_name='机构名称') desc = models.TextField(verbose_name='机构描述') click_nums = models.IntegerField(default=0, verbose_name='点击数') fav_nums = models.IntegerField(default=0, verbose_name='收藏数') image = models.ImageField(upload_to='org/%Y/%m', max_length=100, blank=True, null=True, verbose_name='封面图') address = models.CharField(max_length=150, verbose_name='机构地址') city = models.ForeignKey(CityDict, on_delete=models.CASCADE, verbose_name='所在城市') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '课程机构' def __str__(self): return self.name # 机构里的讲师信息 class Teacher(models.Model): org = models.ForeignKey(CourseOrg, on_delete=models.CASCADE, related_name='teachers', verbose_name='所属机构') name = models.CharField(max_length=50, verbose_name='讲师名称') work_years = models.IntegerField(default=0, verbose_name='工作年限') work_company = models.CharField(max_length=50, verbose_name='就职公司') work_position = models.CharField(max_length=50, verbose_name='公司职位') points = models.CharField(max_length=50, verbose_name=u"教学特点") click_nums = models.IntegerField(default=0, verbose_name=u"点击数") fav_nums = models.IntegerField(default=0, verbose_name=u"收藏数") add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间") class Meta: verbose_name_plural = verbose_name = '讲师' def __str__(self): return self.name ``` ### 同步organization数据库 settings.py添加organization应用 ```python INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'users', 'courses', 'organization', ] ``` 同步数据库 ```python manage.py@DjangoOnlineLearningPlatform > makemigrations organization manage.py@DjangoOnlineLearningPlatform > migrate organization ``` ## 用户操作operation 分析需要那些表: * 用户可以提交我要学习的个人需求。 * 学员的课程评论信息 * 收藏:可以收藏公开课, 授课讲师, 授课机构, 用户消息提醒。 * 个人中心:我的课程说明用户和课程之间的学习关系也需要保存。 模型设计 * UserAsk - 用户咨询 * CourseComments - 用户评论 * UserFavorite - 用户收藏 * UserMessage - 用户消息 * UserCourses- 用户学习的课程(用户点击我要学习记录的关联表) 点击Tools 菜单下 Run manage.py Task ```python manage.py@DjangoOnlineLearningPlatform > startapp operation ``` ### 用户操作models ```python from datetime import datetime from django.db import models from users.models import UserProfile from courses.models import Course # 用户我要学习表单 class UserAsk(models.Model): name = models.CharField(max_length=20, verbose_name='姓名') mobile = models.CharField(max_length=11, verbose_name='手机号') course_name = models.CharField(max_length=50, verbose_name='课程名') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '用户咨询' def __str__(self): return self.name + ' 咨询 ' + self.course_name # 用户对于课程评论 class CourseComments(models.Model): # 会涉及两个外键: 1. 用户, 2. 课程。import进来 course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='课程') user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name='用户') comments = models.CharField(max_length=300, verbose_name='评论') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '课程评论' def __str__(self): return self.user.username + ' 评论' + self.course.name # 用户对于课程,机构,讲师的收藏 class UserFavorite(models.Model): # 会涉及四个外键。用户,课程,机构,讲师import TYPE_CHOICES = ( (1, "课程"), (2, "课程机构"), (3, "讲师") ) user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name='用户') # 表明收藏的数据id fav_id = models.IntegerField(default=0, verbose_name='数据id') fav_type = models.IntegerField(choices=TYPE_CHOICES, default=1, verbose_name='收藏类型') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '用户收藏' def __str__(self): return self.user.username + ' 收藏' # 用户消息 class UserMessage(models.Model): # 因为我们的消息有两种:发给全员和发给某一个用户。 # 所以如果使用外键,每个消息会对应要有用户。很难实现全员消息。 # 为0发给所有用户,不为0就是发给用户的id user = models.IntegerField(default=0, verbose_name="接收用户") message = models.CharField(max_length=500, verbose_name="消息内容") has_read = models.BooleanField(default=False, verbose_name="是否已读") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间") class Meta: verbose_name_plural = verbose_name = '用户消息' def __str__(self): return self.message # 用户学习课程 class UserCourse(models.Model): # 会涉及两个外键: 1. 用户, 2. 课程。import进来 course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name="课程") user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name="用户") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间") class Meta: verbose_name = u"用户课程" verbose_name_plural = verbose_name def __str__(self): return self.user.username + ' 学习 ' + self.course.name ``` ### 同步operation数据库 settings.py添加operation ```python INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'users', 'courses', 'organization', 'operation', ] ``` 执行同步 ```python manage.py@DjangoOnlineLearningPlatform > makemigrations operation manage.py@DjangoOnlineLearningPlatform > migrate operation ``` ## Django2 on_delete配置 ```python TypeError: __init__() missing 1 required positional argument: 'on_delete' ``` 这是因为在2中,外键关系必须指明删除时的操作。 比如:出租车都归属于出租车公司。如果出租车公司倒闭了,那这些汽车该怎么处理。 必须自己指明: 我觉得可以直接进行级联删除。 django提供了: * CASCADE * PROTECT * SET_NULL * SET_DEFAULT 等选项。选择了CASCADE删除。 将(dajngo 2)项目中所有的外键修改为如下面代码所示: 也就是添加了`on_delete=models.CASCADE`使其级联删除。 ## App集中管理 在项目下新建Python的package: apps ![BLOG_20190604_133245_28](/media/blog/images/2019/06/BLOG_20190604_133245_28.png "博客图集BLOG_20190604_133245_28.png") 把四个app都拖进apps中去。 ![BLOG_20190604_133240_65](/media/blog/images/2019/06/BLOG_20190604_133240_65.png "博客图集BLOG_20190604_133240_65.png") 去掉searchfor的勾选。拖进去之后会报错,说找不到那些import的模块了。 ![BLOG_20190604_133235_32](/media/blog/images/2019/06/BLOG_20190604_133235_32.png "博客图集BLOG_20190604_133235_32.png") 解决方案:在apps上右键**Mark Directory as**为**sourceRoot**。根目录下找不到的,会去apps下搜索。 但是这时候cmd下运行python manage runserver xxx还是会报错。 将apps添加到python搜索目录下,修改settings.py ```python import os import sys # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) # 添加apps搜索路径 ``` ## 设置静态资源和文件上传路径 ### 设置静态资源路径 settings.py增加 ```python STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] # STATIC_ROOT = os.path.join(BASE_DIR, 'static') ``` ### 设置文件上传路径 ```python # 设置我们上传文件的路径 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') ``` ### 修改项目中urls.py文件 ```python from django.contrib import admin from django.urls import path from django.conf.urls.static import static from django.conf import settings urlpatterns = [ path('admin/', admin.site.urls), ] if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ``` 这样,在后台才会正常返回图片或文件的链接。

很赞哦! (4)

文章交流

  • emoji
0人参与,0条评论

当前用户

未登录,点击   登录

站点信息

  • 建站时间:网站已运行2077天
  • 系统信息:Linux
  • 后台程序:Python: 3.8.10
  • 网站框架:Django: 3.2.6
  • 文章统计:256 篇
  • 文章评论:60 条
  • 腾讯分析网站概况-腾讯分析
  • 百度统计网站概况-百度统计
  • 公众号:微信扫描二维码,关注我们
  • QQ群:QQ加群,下载网站的学习源码
返回
顶部
标题 换行 登录
网站