项目介绍和环境配置和数据库表的设计

2018-11-15  本文已影响0人  莫辜负自己的一世韶光

主要用用到的技术知识点

通过业务分析设计django的每个app,设计app下的model。设计外键关系,通过django的migrate设计生成数据表。

然后将这些model注册到xadmin当中。为每个model配置搜索,过滤字段,以及列表页的显示字段。配置xadmin的主题选择功能。

实现所有后台功能 & 面试中经常被提及的web开发知识。

几乎所有的django常用模块:

xadmin的扩展知识

掌握更多的定制功能:

还会用到一些开源的django开源库


1. virtualenv的安装和配置

virtualenv介绍

每个应用可能需要各自一套独立的python运行环境.virtualenv就是为了给每个应用创建一套隔离的Python运行环境.

virtualenv的优点:

安装virtualenv

进入cmd
pip install virtualenv
virtualenvwrapper安装
pip install virtualenvwrapper-win

创建虚拟环境

创建之前,先加一个WORKON_HOME的环境变量


deactivate
workon
workon xxx
mkvirtualenv mx_online
mkvirtualenv -p C:\Python36\python.exe mx_online

进入虚拟环境,然后安装相应的必备的依赖包

进入虚拟环境安装相关的依赖包

pip install -r C:\Envs\requirements.txt

requirements.txt

Django==1.11.6
django-crispy-forms==1.7.2
django-formtools==2.1
django-import-export==1.0.1
django-pure-pagination==0.3.0
django-ranged-response==0.2.0
django-simple-captcha==0.5.6
et-xmlfile==1.0.1
future==0.16.0
httplib2==0.9.2
jdcal==1.4
odfpy==1.3.6
openpyxl==2.5.6
Pillow==5.2.0
pytz==2018.5
PyYAML==3.13
six==1.11.0
tablib==0.12.1
unicodecsv==0.14.1
xlrd==1.1.0
xlwt==1.3.0

安装完毕之后,创建一个Django项目,名字为MxOnline, 环境继承自刚才的虚拟环境

image.png

将项目关联到github,创建远程仓库

2.Django-app 设计

数据库设计

根据app设计models

授课机构提供讲师录制课程,学院完成在线学习.

app大致分为4个模块

users - 用户模块
course - 课程模块
organization - 机构教师模块
operation - 用户操作模块

3.setting.py设置

首先确保你的电脑里有mysql应用,然后安装pymysql,分为两个步骤:

pip install pymysql
# 然后setting.py中写入以下代码
image.png

还要在MxOnline/init.py中,声明运用pymysql

import pymysql

pymysql.install_as_MySQLdb()

进行数据库初始化,创建数据库表.注意,之前必须在数据里创建上面设置里面对应的表名mxonline

点击tools下的Run manage.py Task 或者ctrl + alt + r打开manage.py操作面板

makemigrations
migrate

将页面显示的语言设置为中文,并且时间设置为上海时间

# 语言改为中文
LANGUAGE_CODE = 'zh-hans'

# 时区改为上海
TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

# 数据库存储使用时间,True时间会被存为UTC的时间
USE_TZ = False

然后运行就可以看到这个界面

在manage.py Task下创建app users

startapp users

编辑我们的model设计user表

系统自动生成的user表如下:

个人中心页面:

可以看到我们还需要:

User表的自定方法,如果既想保留原有的字段,又想有新字段.
可以在models.py中创建UserProfile 继承自AbstractUser,然后添加新的属性字段.
然后在setting.py中重载AUTH_USER_MODEL

# 此处重载是为了使我们的UserProfile生效
AUTH_USER_MODEL = "users.UserProfile"

models.py中添加如下代码

from django.contrib.auth.models import AbstractUser
from django.db import models


class UserProfile(AbstractUser):
    # 自定义的性别选择规则
    GENDER_CHOICES = (
        ('male', '男'),
        ('female', '女')
    )

    # 昵称
    nick_name = models.CharField(max_length=50, verbose_name='昵称', default='')
    # 生日可以为空,null=True是针对数据库的,而blank=True是针对表单的.
    # 表示该字段在数据库中可以为空,同时提交表单的时候可以,该字段可以不填.
    birthday = models.DateField(null=True, blank=True, verbose_name='生日')
    # 性别,只能是男或者女.默认是女
    gender = models.CharField(max_length=6, choices=GENDER_CHOICES, default='female', verbose_name='性别')
    # 地址
    address = models.CharField(max_length=100, default='', verbose_name='地址')
    # 电话
    mobile = models.CharField(max_length=11, null=True, blank=True, verbose_name='电话')

    # 头像 默认使用default.png
    image = models.ImageField(upload_to='image%Y%m',
                              default='image/default.png',
                              max_length=100,
                              verbose_name='头像')

    class Meta:
        verbose_name = '用户信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return "<UserProfile: >{}".format(self.username)

在setting.py中注册app

INSTALL_APPS = [
      ...
     'users'
]

因为Image字段需要用到pillow所以需要安装该库

pip install pillow

然后执行

makemigrations
migrate

如果出现以下错误

django.db.migrations.exceptions.InconsistentMigrationHistory: Migration
admin.0001_initial is applied before its dependency users.0001_initial on
database 'default'

解决方案:

删除数据库中 除了auth_user的其他表

删除表的时候,可能会遇到删不掉的情况,就先删除其他的,带有外键关联的表,需要先删除有外键的表

然后执行命令:

makemigrations
migrate
makemigrations users
migrate users

共十一张表

创建另外三个app,manage.py Task下

startapp courses
startapp organization
startapp operation

循环引用:

设计app时每个app都有model

如图:我们在user中定义usercourse记录用户学习的课程.会有两个外键:user和course
我们就会import Courses.models

如果用户对课程的评论放到Courses.models当中.评论我们需要保存相应的用户.我们就会import User.models

两个Models互相引用,就会出现循环导入,a和b相互调用,造成等待.

解决循环引用: 分层设计

目前已有app:users courses oranization operation

另外一个app operation高于这些app的层级.上一层的app可以import下层的app

user表中还需要添加的(前提是这些功能比较独立,不会和其他的模块产生import,这些顶层的model可以放到user的models.py中)

users/models.py

# 邮箱验证码
class EmailVerifyRecord(models.Model):
    SEND_CHOICES = (
        ('register', '注册'),
        ('forget', '找回密码'),
        ('update_email', '修改邮箱'),

    )
    code = models.CharField(max_length=20, verbose_name='验证码')
    email = models.EmailField(max_length=50, verbose_name='邮箱')
    # 验证码的用途,注册和找回密码的时候都可以使用,所以要分类
    send_type = models.CharField(choices=SEND_CHOICES, max_length=20, verbose_name='验证码类型')
    # 这里的now得去掉(),不去掉会根据编译时间。而不是根据实例化时间。
    send_time = models.DateTimeField(default=datetime.now, verbose_name='发送时间')

    class Meta:
        verbose_name = '邮箱验证码'
        verbose_name_plural = verbose_name

    def __str__(self):
        return "<EmailVerifyRecord: >{}".format(self.code)


class Banner(models.Model):
    title = models.CharField(max_length=100, verbose_name='标题')
    # 保存到数据库的时候存储的是url地址
    image = models.ImageField(max_length=100, upload_to='banner/%Y/%m', verbose_name='轮播图')
    url = models.URLField(max_length=200, verbose_name='访问地址')
    # 控制轮播图的顺序
    index = models.IntegerField(default=100, verbose_name='顺序')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')

    class Meta:
        verbose_name = '轮播图'
        verbose_name_plural = verbose_name

    def __str__(self):
        return "{0}(位于第{1}位)".format(self.title, self.index)

Courses/models.py的编写

课程本身需要一张表

点进去之后

结构: 课程本身 -- (一对多) > 章节 (一对多) -> 视频信息
资源下载放在课程里面的,一个课程对应多个资源.

共四张表:
课程本身(一对多)章节 -> (一对多) -> 视频信息 & 资源表


课程表的编写,注意他们之间的表的对应关系

from datetime import datetime

from django.db import models


# 课程信息表
class Course(models.Model):
    DegreeChoices = (
        ('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(choices=DegreeChoices, max_length=2)
    learn_time = 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='courses/%Y/%m', max_length=100, 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 = verbose_name

    def __str__(self):
        return self.name


# 章节表   课程和章节的对应关系 (一对多)->(课程对章节)
class Lesson(models.Model):
    # 外键关联
    course = models.ForeignKey(Course, verbose_name='课程')
    name = models.CharField(max_length=100, verbose_name='章节名')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')

    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='章节')
    name = models.CharField(max_length=100, verbose_name='视频名')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')

    class Meta:
        verbose_name = '视频'
        verbose_name_plural = verbose_name

    def __str__(self):
        return "<<{0}>>章节的视频{1}".format(self.lesson, self.name)


# 课程资源表
class ResourceCourse(models.Model):
    # course相关
    course = models.ForeignKey(Course, verbose_name='课程')
    name = models.CharField(max_length=100, verbose_name='名称')
    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 = '课程资源'
        verbose_name_plural = verbose_name

    def __str__(self):
        return "<<{0}>> 课程的资源: {1}".format(self.course, self.name)

通过Structure可以看到我们刚才设计了四张表

organization(课程机构表)的编写 organization/models.py

课程是属于机构,机构有机构类别,城市等字段.讲师实体.
我要学习的提交表单会与用户关联,存放在机构.


点击具体的课程:


其中课程数,学习人数可以动态统计.机构地址,机构经典课程.

机构讲师,机构课程可以通过外键获取到,不保存到机构中


对应的models.py如下

from datetime import datetime

from django.db import models


class CityDict(models.Model):
    name = models.CharField(max_length=20, verbose_name='城市')
    desc = models.CharField(max_length=200, verbose_name='描述')
    add_time = models.DateTimeField(default=datetime.now)

    class Meta:
        verbose_name = '城市'
        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', verbose_name='封面图')
    address = models.CharField(max_length=150, verbose_name='机构地址')

    # 城市外键
    city = models.ForeignKey(CityDict, verbose_name='所在城市')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')

    class Meta:
        verbose_name = '课程机构'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '课程机构: {}'.format(self.name)


# 教师信息表
class Teacher(models.Model):
    # 外键,一个机构可以对应多个老师
    org = models.ForeignKey(CourseOrg, 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=100, verbose_name='公司职位')
    points = models.CharField(max_length=50, verbose_name='教学特点')
    click_nums = models.IntegerField(default=0, verbose_name='点击数')
    fav_nums = models.IntegerField(default=0, verbose_name='收藏数')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')

    class Meta:
        verbose_name = '教师'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '[{0}]的教师: {1}'.format(self.org, self.name)

我们可以看到,organization/models.py中一共具有三张表


operation/models.py设计

分析需要哪些表:

from datetime import datetime

from django.db import models

# 用户我要学习表单,用户咨询
from courses.models import Course
from users.models import UserProfile


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 = '用户咨询'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用户: {0} 手机号: {1}'.format(self.name, self.mobile)


# 用户对于课程的评论
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=250, verbose_name='评论')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='评论时间')

    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='用户')
    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 = '用户收藏'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用户({0})收藏了{1} '.format(self.user, self.fav_type)


# 用户消息表
class UserMessage(models.Model):
    # user为0的时候,发送给所有.
    user = models.IntegerField(default=0, verbose_name='接收用户')
    message = models.CharField(max_length=500, verbose_name='消息内容')
    has_read = models.BooleanField(default=False)
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')

    class Meta:
        verbose_name = '用户消息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用户({0})接收了{1} '.format(self.user, self.message)

# 用户课程表
class UserCourse(models.Model):
    # 会涉及两个外键: 1.用户  2.课程
    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 = '用户课程'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '用户({0})学习了{1} '.format(self.user, self.course)

到这里我们所有的models都设计完毕.operation/models.py


settings.py中添加配置app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 注册app
    'users',
    'organization',
    'courses',
    'operation',
]

数据表的生成以及apps目录的建立

打开manage.py 的Task

makemigrations
migrate

生成如下的表:


把我们的四个app放到一个文件夹下.

新建Python的package:apps
然后将四个app拖进去,注意不要选择下面的选项

然后将apps包右键mark为sourceRoot.根目录下找不到,会去apps目录下搜索.

但是这时候cmd下还是会报错

解决方法:

将apps设置到我们的系统搜索目录之下

上一篇下一篇

猜你喜欢

热点阅读