前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >零基础使用Django2.0.1打造在线教育网站(七):数据库字段的定义(上)

零基础使用Django2.0.1打造在线教育网站(七):数据库字段的定义(上)

原创
作者头像
啃饼思录
修改2018-09-10 21:19:33
8770
修改2018-09-10 21:19:33
举报

关于博主

努力与运动兼备~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

代码语言:txt
复制
                 微信公众号:  啃饼思录
代码语言:txt
复制
                 QQ: 2810706745(啃饼小白)

写在前面

本篇笔记主要就是对上篇遗留的2个问题的解决:4个app项目的创建和数据库字段的定义,鉴于篇幅的原因,这里分上下两篇进行介绍。

本篇笔记对应于第七篇代码,对应于github的位置是https://github.com/licheetools/eduline

4个app项目的创建

users app的创建

先点击菜单下的Tools按钮 ,然后点击下拉的 Run manage.py Task按钮,在命令行中输入:

代码语言:txt
复制
startapp users
然后在Navicat中打开我们的数据库eduline,会发现生成了很多表,我们打开其中的auth_user这个表:

下面我简要说明一下表中个字段的含义:

id代表主键, password是密码, last_login 这是Django用于自动记录用户最后登录时间的字段。

is_superuser 表明用户是否是超级用户(后台管理中会用到),

username 表示用户名(该字段不要随便修改),

last_name和first_name分别是姓和名,

email 表示邮箱,

is_staff 表示是否是员工(后台管理中会用到),

is_active 表示用户是否是激活状态,

date_joined 表示注册时间。

这其实是满足不了我们的需求的,因为我们的个人中心通常包括:昵称,性别,生日,地址,手机号,邮箱等信息,所以我们要扩展这些字段来满足我们的需求。

user表的自定义方法官方文档已经给出了,这里开启传送大门https://docs.djangoproject.com/zh-hans/2.0/ref/models/fields/

我们是希望既可以保留原来的字段,又可以新增我们的自定义字段,所以我们需要引入继承我们的AbstractUser这个类。

打开我们的users/models.py文件,添加并修改如下代码:

代码语言:txt
复制
from django.db import models



from datetime import datetime



# Create your models here.

from django.contrib.auth.models import AbstractUser  # 导入需要的类





class UserProfile(AbstractUser):

    # 昵称

    nick\_name=models.CharField(max\_length=50,verbose\_name='昵称',default='')

     # 生日,可以为空

    birday=models.DateTimeField(verbose\_name='生日',null=True,blank=True)

     # 性别,默认为女

    gender=models.CharField(max\_length=6, choices=(('male','男'),('female','女')),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,upload\_to为上传路径,记住图片字段必须有字段最大值

  image=models.ImageField(upload\_to='image/%Y/%m',default='image/default.png',max\_length=100,verbose\_name='图片')

     # meta信息,即后台管理中的名称

    class Meta:

        verbose\_name= '用户信息'

        verbose\_name\_plural=verbose\_name

     # 重载str方法,打印实例会打印username,username为继承自Abstractuser这个类

    def \_\_str\_\_(self):

        return self.username

**注意:**

**1、**按住ctrl然后单击我们的AbstractUser,就可以进入到这个类的定义文件:auth/models.py,这也就是我们之前导入的位置:

看到没,我们之前保留的字段它都有,所以我们只需要继承它就可以了。

**2、**前面说过CharField必须有max_length, 但实际上Imagefield也是Charfield,所以也要有max_length。

**3、**因为使用到了Imagefield字段,所以需要用到Pillow这个库,我们可以通过**Pycharm**或者**pip**安装它。

注册APP和重载AUTH_USER_MODEL

注册APP

打开eduline/settings.py文件,找到第30行代码,最底下加上我们的app名称。

代码语言:txt
复制
INSTALLED\_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'users',

]

重载AUTH_USER_MODEL

打开eduline/settings.py文件,在刚才代码的底下加上重载我们的UserProfile代码:

代码语言:txt
复制
INSTALLED\_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'users',

]

# 重载UserProfile使其生效

AUTH\_USER\_MODEL='users.UserProfile'

数据库更新

点击**Tools** 菜单下 **Run manage.py Task**,运行我们的**makemigrations users**和**migrate users**命令。你会发现运行前者没问题,运行后者却出了问题:

代码语言:txt
复制
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001\_initial is applied before its dependency users.0001\_initial on database 'default'.
其实这个问题就是你之前已经定义了userProfile并且还设置了重载它的语句,现在又来定义它,它是不会再给你提供那么多的初始表的:
所以我们需要删除除了auth_user以外的其他表,如果一次删除不了(那是因为表与表之间存在外键联系)就一个个的删除:

现在再来点击**Tools** 菜单下 **Run manage.py Task**,按顺序运行如下命令:

代码语言:txt
复制
makemigrations

migrate

makemigrations users

migrate users

**注意:**只运行后面那2个命令是不可以的,会缺少部分表!!!

看到没,这次没有问题出现了:
打开数据库,看一下我们的表,一共有11个表:
打开这个自定义表(users_usersprofile),你会发现我们需要的字段都有了:

注意一下

我们以后不要在初始化的时候就执行makemigrations & migrate操作,应当在我们设计完userProfile(自定义字段)之后再执行该操作,那样就不会报错了。

至此我们完成了第一个app的配置和其自定义字段的设计!

循环引用

看下面这个图:

我们通常会在user中定义userCourse这个字段,用来记录用户学习的课程,它会有两个外键:user和course。所以在用到的时候,我们需要import Courses.models。

同样,如果用户对于某个课程需要评论,那么我们需要定义CourseComment这个字段,而且它肯定会放在 Courses.models当中。所以在用到的时候,我们又需要import User.models。

这是只有2个app的情况,当还有更多的情况:3个,4个,5个...apps时,循环调用import会出错导致系统不能正确识别,而且最起码会造成时间上的等待。那么有没有好的方法来解决这个问题呢?答案是有的!可以采用分层设计的思想来解决这个难题。

分层设计

在前面的第六篇笔记中我们已经说过,准备新建4个app,其中的3个apps:

**(users)用户版块**,**(course)课程版块**,**(organization)授课教师与授课机构板块**, 就是一些常规的信息存储,而第4个**(operation)用户操作板块**就是采用分层设计的思想来设计的,而且我们保证**operation**这个app的优先级高于其他3个,所以可以随时import这些底层的apps。各个apps的层级关系如下图所示:

在users这个app中,我们自定义了UserProfile这个表用来覆盖系统默认的user表。这样其实我们这个users应用已经设计完了。不过呢,通过研究我们发现有些功能是非常独立的,我们为了平衡一些app的代码量,可以将它们放在这个users项目里面。

EmailVerifyRecord - 邮箱验证码 Banner - 轮播图

邮箱验证码的设计

验证码分三种类型,分别用于不同的功能:注册;找回密码;修改邮箱,所以在设计验证码类型的时候注意选择的条件,通常验证码包括这些字段:code,email,send\_type,send\_time

我们打开users/models.py文件,接着之前的代码在后面添加如下内容:

代码语言:txt
复制
from datetime import datetime





class EmailVerifyRecord(models.Model):

    code = models.CharField(max\_length=20, verbose\_name="验证码")

    email = models.EmailField(max\_length=50, verbose\_name="邮箱")

    send\_type = models.CharField(verbose\_name="验证码类型", 

choices=(('register', '注册'), ('forget', '找回密码'), ('update\_email', '修改邮箱')), max\_length=30)



# 这里的now得去掉(),如果不去掉则会根据编译时间,而不是我们要的实例化时间。

    send\_time = models.DateTimeField(verbose\_name="发送时间", default=datetime.now)   

 

    class Meta:

        verbose\_name = "邮箱验证码"

        verbose\_name\_plural = verbose\_name



    def \_\_str\_\_(self):

        return self.email   #这里很重要,否则在后台就显示不出Meta信息

轮播图的设计

轮播图是一个可以自动切换图片的效果,它包括标题,具体的图片,点击图片后的跳转地址,图片的轮播顺序,添加时间等要素:title,image,url,index,add\_time

我们打开users/models.py文件,接着之前的代码在后面添加如下内容:

代码语言:txt
复制
class Banner(models.Model):

    title = models.CharField(max\_length=100, verbose\_name="标题")

    image = models.ImageField(max\_length=100, upload\_to='banneer/%Y/&m',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 = "轮播图"

        verbose\_name\_plural = verbose\_name



    def \_\_str\_\_(self):

        return self.title  # 这里很重要,否则在后台就显示不出Meta信息

你可能会问,为什么不把与用户相关的评论,点赞,学习的课程,课程进度等信息也放到这个app中呢?其实是因为那些信息的相关性很大,经常是循环引用,所以我们把那些信息都放到operation这个app中。

我们把鼠标移至models.py这个文件上,再点击右侧的structure,可以发现我们刚才新创建的3个类(其实就是数据库里的数据表):

至此第一个app应用的数据库字段定义算是完成了,下面大家可以思考一下其他3个应用的数据库字段的定义应该是怎样的,给大家留点时间思考一下,我们下一篇笔记再来介绍!下面介绍一个Python的规范,可以让你的代码更具有可读性和维护性。

PEP8规范

(一) 代码的编排

**1、 缩进**。每行需要4个空格的缩进,不要使用Tap键,更不能混合使用Tap键和空格。

**2 、**每行最大长度79,换行可以使用反斜杠,但最好使用圆括号。换行点要在操作符的后边敲回车。

**3 、**类和top-level函数定义之间空两行;类中的方法定义之间空一行;函数内逻辑无关段落之间空一行;其他地方尽量不要再空行。

(二 )文档的编排

**1、** 模块内容的顺序:模块说明和docstring—import—globals&constants—其他定义。其中import部分,又按标准、第三方和自己编写顺序依次排放,之间空一行。

代码语言:txt
复制
from django.db import models

from datetime import datetime

# Create your models here.

from django.contrib.auth.models import AbstractUse



# 自己定义代码放置处

**2 、**不要在一行import多个库,比如import os, sys,虽说没有错误但是并不推荐。

**3、** 如果采用from xx import xx的方式来引用某个库,可以省略module.,但是可能会出现命名的冲突,所以这时就要采用import xx的方式。

(三)空格的使用

总体原则,避免不必要的空格。

**1、** 各种右括号前不要加空格。

**2、** 逗号、冒号、分号前不要加空格。

**3 、**函数的左括号前不要加空格。如function(1)。

**4 、**序列的左括号前不要加空格。如list2。

**5、**操作符左右各加一个空格,不要为了对齐增加空格。

**6 、**函数默认参数使用的赋值符左右省略空格。

**7、**不要将多句语句写在同一行,尽管使用允许。

**8、** if/for/while语句中,即使执行语句只有一句,也必须另起一行。

(四)命名的规范

总体原则,新编代码必须按下面命名风格进行,现有库的编码尽量保持风格。

**1 、**尽量单独使用小写字母‘l’,大写字母‘O’等容易混淆的字母。

**2、** 模块命名尽量短小,使用全部小写的方式,可以使用下划线。

**3、** 包命名尽量短小,使用全部小写的方式,不可以使用下划线。

**4、** 类的命名使用CapWords的方式,模块内部使用的类采用_CapWords的方式。

**5、** 异常命名使用CapWords+Error后缀的方式。

**6 、**全局变量尽量只在模块内有效,类似C语言中的static。实现方法有两种,一是__all__机制;二是前缀一个下划线。

**7 、**函数命名使用全部小写的方式,可以使用下划线。

**8 、**常量命名使用全部大写的方式,可以使用下划线。

**9 、**类的属性(方法和变量)命名使用全部小写的方式,可以使用下划线。

**10、**类的属性有3种作用域public、non-public和subclass API,可以理解成C++中的public、private、protected,non-public属性前,前缀一条下划线。

**11 、**类的属性若与关键字名字冲突,后缀一下划线,尽量不要使用缩略等其他方式。

**12 、**为避免与子类属性命名冲突,在类的一些属性前,前缀两条下划线。比如:类Foo中声明__a,访问时,只能通过Foo._Foo__a,避免歧义。如果子类也叫Foo,那就无能为力了。

**13 、**类的方法第一个参数必须是**self**,而静态方法第一个参数必须是**cls**。

(五)编码的建议

**1、**编码中考虑到其他python实现的效率等问题,比如运算符‘+’在CPython(Python)中效率很高,都是Jython中却非常低,所以应该采用.join()的方式。

**2 、**尽可能使用‘is’‘is not’取代‘==’,比如if x is not None 要优于if x。

**3 、**使用基于类的异常,每个模块或包都有自己的异常类,此异常类继承自Exception。

**4 、**异常中不要使用裸露的except,except后跟具体的exceptions。

**5 、**异常中try的代码尽可能少。比如:

代码语言:txt
复制
try:

value = collection[key]

except KeyError:

return key\_not\_found(key)

else:

return handle\_value(value)

要优于

代码语言:txt
复制
try:

# Too broad!

return handle\_value(collection[key])

except KeyError:

# Will also catch KeyError raised by handle\_value()

return key\_not\_found(key)

**6 、**使用startswith() and endswith()代替切片进行序列前缀或后缀的检查。比如:

Yes: if foo.startswith(‘bar’):优于No: if foo[:3] == ‘bar’:

**7 、**使用isinstance()比较对象的类型。比如:

Yes: if isinstance(obj, int):优于No: if type(obj) is type(1):

**8、** 判断序列空或不空,有如下规则:

代码语言:txt
复制
Yes: if not seq:

if seq:

优于

代码语言:txt
复制
No: if len(seq)

if not len(seq)

**9 、**字符串不要以空格收尾。

**10、**二进制数据判断使用 if boolvalue的方式。

如果你想获得更多关于PEP8的信息,可以查阅这篇信息PEP8 Python 编码规范整理或者官方文档PEP8的官方文档

至此,我们第七篇:在线教育网站的数据库字段的定义(上)就到此结束了,感谢你的赏阅。下一篇,我们就完善其余3个apps应用的数据库字段的定义。

本篇笔记对应于第七篇代码,对应于github的位置是https://github.com/licheetools/eduline

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于博主
  • 写在前面
  • 4个app项目的创建
  • users app的创建
  • 注册APP和重载AUTH_USER_MODEL
    • 注册APP
      • 重载AUTH_USER_MODEL
        • 数据库更新
        • 注意一下
          • 循环引用
            • 分层设计
              • 邮箱验证码的设计
                • 轮播图的设计
                • PEP8规范
                  • (一) 代码的编排
                    • (二 )文档的编排
                      • (三)空格的使用
                        • (四)命名的规范
                          • (五)编码的建议
                          相关产品与服务
                          数据库
                          云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档