Python自学Day42 深入模型

深入模型

在上一个章节中,我们提到了Django是基于MVC架构的Web框架,MVC架构追求的是“模型”和“视图”的解耦合。所谓“模型”说得更直白一些就是数据(的表示),所以通常也被称作“数据模型”。在实际的项目中,数据模型通常通过数据库实现持久化操作,而关系型数据库在过去和当下都是持久化的首选方案,下面我们通过完成一个投票项目来讲解和模型相关的知识点。投票项目的首页会展示某在线教育平台所有的学科;点击学科可以查看到该学科的老师及其信息;用户登录后在查看老师的页面为老师投票,可以投赞成票和反对票;未登录的用户可以通过登录页进行登录;尚未注册的用户可以通过注册页输入个人信息进行注册。在这个项目中,我们使用MySQL数据库来实现数据持久化操作。

创建项目和应用

我们首先创建Django项目vote并为其添加虚拟环境和依赖项。接下来,在项目下创建名为polls的应用和保存模板页的文件夹tempaltes,项目文件夹的结构如下所示。

Python自学Day42 深入模型

根据上面描述的项目需求,我们准备了四个静态页面,分别是展示学科的页面subjects.html,显示学科老师的页面teachers.html,登录页面login.html,注册页面register.html,稍后我们会将静态页修改为Django项目所需的模板页。

配置关系型数据库MySQL

  • 在MySQL中创建数据库,创建用户,授权用户访问该数据库。

  • 在MySQL中创建保存学科和老师信息的二维表(保存用户信息的表稍后处理)。

  • 在虚拟环境中安装连接MySQL数据库所需的依赖项。

说明:如果因为某些原因无法安装mysqlclient三方库,可以使用它的替代品pymysql,pymysql是用纯Python开发的连接MySQL的Python库,安装更容易成功,但是需要在Django项目文件夹的__init__.py中添加如下所示的代码。

如果使用Django 2.2及以上版本,还会遇到PyMySQL跟Django框架的兼容性问题,兼容性问题会导致项目无法运行,需要按照GitHub上PyMySQL仓库Issues中提供的方法进行处理。总体来说,使用pymysql会比较麻烦,强烈建议大家首选安装mysqlclient。

  • 修改项目的settings.py文件,首先将我们创建的应用polls添加已安装的项目(INSTALLED_APPS)中,然后配置MySQL作为持久化方案。

在配置ENGINE属性时,常用的可选值包括:

其他的配置可以参考官方文档中数据库配置的部分。

  • Django框架提供了ORM来解决数据持久化问题,ORM翻译成中文叫“对象关系映射”。因为Python是面向对象的编程语言,我们在Python程序中使用对象模型来保存数据,而关系型数据库使用关系模型,用二维表来保存数据,这两种模型并不匹配。使用ORM是为了实现对象模型到关系模型的双向转换,这样就不用在Python代码中书写SQL语句和游标操作,因为这些都会由ORM自动完成。利用Django的ORM,我们可以直接将刚才创建的学科表和老师表变成Django中的模型类。

我们可以对自动生成的模型类稍作调整,代码如下所示。

说明:模型类都直接或间接继承自Model类,模型类跟关系型数据库的二维表对应,模型对象跟表中的记录对应,模型对象的属性跟表中的字段对应。如果对上面模型类的属性定义不是特别理解,可以看看本文后面提供的“模型定义参考”部分的内容。

使用ORM完成模型的CRUD操作

有了Django框架的ORM,我们可以直接使用面向对象的方式来实现对数据的CRUD(增删改查)操作。我们可以在PyCharm的终端中输入下面的命令进入到Django项目的交互式环境,然后尝试对模型的操作。

新增

删除

更新

查询

  • 查询所有对象。

  • 查询单个对象。

排序。

切片(分页查询)。

计数。

高级查询。

利用Django后台管理模型

在创建好模型类之后,可以通过Django框架自带的后台管理应用(admin应用)实现对模型的管理。虽然实际应用中,这个后台可能并不能满足我们的需求,但是在学习Django框架时,我们可以利用admin应用来管理我们的模型,同时也通过它来了解一个项目的后台管理系统需要哪些功能。使用Django自带的admin应用步骤如下所示。

  • 将admin应用所需的表迁移到数据库中。admin应用本身也需要数据库的支持,而且在admin应用中已经定义好了相关的数据模型类,我们只需要通过模型迁移操作就能自动在数据库中生成所需的二维表。

  • 创建访问admin应用的超级用户账号,这里需要输入用户名、邮箱和口令。

  • 运行项目,在浏览器中访问http://127.0.0.1:8000/admin,输入刚才创建的超级用户账号和密码进行登录。

登录后进入管理员操作平台。

Python自学Day42 深入模型

注意,我们暂时还没能在admin应用中看到之前创建的模型类,为此需要在polls应用的admin.py文件中对需要管理的模型进行注册。

  • 注册模型类。

注册模型类后,就可以在后台管理系统中看到它们。

Python自学Day42 深入模型

  • 对模型进行CRUD操作。

可以在管理员平台对模型进行C(新增)、R(查看)、U(更新)、D(删除)操作,如下图所示。

添加学科。

Python自学Day42 深入模型

查看所有学科。

Python自学Day42 深入模型

删除和更新学科。

Python自学Day42 深入模型

注册模型管理类。

可能大家已经注意到了,刚才在后台查看部门信息的时候,显示的部门信息并不直观,为此我们再修改admin.py文件,通过注册模型管理类,可以在后台管理系统中更好的管理模型。

Python自学Day42 深入模型

Python自学Day42 深入模型

为了更好的查看模型,我们为Subject类添加__str__魔法方法,并在该方法中返回学科名字。这样在如上图所示的查看老师的页面上显示老师所属学科时,就不再是Subject object(1)这样晦涩的信息,而是学科的名称。

实现学科页和老师页效果

修改polls/views.py文件,编写视图函数实现对学科页和老师页的渲染。

修改templates/subjects.html和templates/teachers.html模板页。

subjects.html

teachers.html

修改vote/urls.py文件,实现映射URL。

到此为止,页面上需要的图片(静态资源)还没有能够正常展示,我们在下一章节中为大家介绍如何处理模板页上的需要的静态资源。

补充内容

  1. Django模型最佳实践
  2. 正确的为模型和关系字段命名。
  3. 设置适当的related_name属性。
  4. 用OneToOneField代替ForeignKeyField(unique=True)。
  5. 通过“迁移操作”(migrate)来添加模型。
  6. 用NoSQL来应对需要降低范式级别的场景。
  7. 如果布尔类型可以为空要使用NullBooleanField。
  8. 在模型中放置业务逻辑。
  9. 用<ModelName>.DoesNotExists取代ObjectDoesNotExists。
  10. 在数据库中不要出现无效数据。
  11. 不要对QuerySet调用len()函数。
  12. 将QuerySet的exists()方法的返回值用于if条件。
  13. 用DecimalField来存储货币相关数据而不是FloatField。
  14. 定义__str__方法。
  15. 不要将数据文件放在同一个目录中。

模型定义参考

字段

对字段名称的限制

  • 字段名不能是Python的保留字,否则会导致语法错误
  • 字段名不能有多个连续下划线,否则影响ORM查询操作

Django模型字段类

字段类 说明
AutoField 自增ID字段
BigIntegerField 64位有符号整数
BinaryField 存储二进制数据的字段,对应Python的bytes类型
BooleanField 存储True或False
CharField 长度较小的字符串
DateField 存储日期,有auto_now和auto_now_add属性
DateTimeField 存储日期和日期,两个附加属性同上
DecimalField 存储固定精度小数,有max_digits(有效位数)和decimal_places(小数点后面)两个必要的参数
DurationField 存储时间跨度
EmailField 与CharField相同,可以用EmailValidator验证
FileField 文件上传字段
FloatField 存储浮点数
ImageField 其他同FileFiled,要验证上传的是不是有效图像
IntegerField 存储32位有符号整数。
GenericIPAddressField 存储IPv4或IPv6地址
NullBooleanField 存储True、False或null值
PositiveIntegerField 存储无符号整数(只能存储正数)
SlugField 存储slug(简短标注)
SmallIntegerField 存储16位有符号整数
TextField 存储数据量较大的文本
TimeField 存储时间
URLField 存储URL的CharField
UUIDField 存储全局唯一标识符

字段属性

通用字段属性

选项 说明
null 数据库中对应的字段是否允许为NULL,默认为False
blank 后台模型管理验证数据时,是否允许为NULL,默认为False
choices 设定字段的选项,各元组中的第一个值是设置在模型上的值,第二值是人类可读的值
db_column 字段对应到数据库表中的列名,未指定时直接使用字段的名称
db_index 设置为True时将在该字段创建索引
db_tablespace 为有索引的字段设置使用的表空间,默认为DEFAULT_INDEX_TABLESPACE
default 字段的默认值
editable 字段在后台模型管理或ModelForm中是否显示,默认为True
error_messages 设定字段抛出异常时的默认消息的字典,其中的键包括null、blank、invalid、invalid_choice、unique和unique_for_date
help_text 表单小组件旁边显示的额外的帮助文本。
primary_key 将字段指定为模型的主键,未指定时会自动添加AutoField用于主键,只读。
unique 设置为True时,表中字段的值必须是唯一的
verbose_name 字段在后台模型管理显示的名称,未指定时使用字段的名称

ForeignKey属性

  1. limit_choices_to:值是一个Q对象或返回一个Q对象,用于限制后台显示哪些对象。
  2. related_name:用于获取关联对象的关联管理器对象(反向查询),如果不允许反向,该属性应该被设置为’+’,或者以’+’结尾。
  3. to_field:指定关联的字段,默认关联对象的主键字段。
  4. db_constraint:是否为外键创建约束,默认值为True。
  5. on_delete:外键关联的对象被删除时对应的动作,可取的值包括django.db.models中定义的:
    • CASCADE:级联删除。
    • PROTECT:抛出ProtectedError异常,阻止删除引用的对象。
    • SET_NULL:把外键设置为null,当null属性被设置为True时才能这么做。
    • SET_DEFAULT:把外键设置为默认值,提供了默认值才能这么做。

ManyToManyField属性

  1. symmetrical:是否建立对称的多对多关系。
  2. through:指定维持多对多关系的中间表的Django模型。
  3. throughfields:定义了中间模型时可以指定建立多对多关系的字段。
  4. db_table:指定维持多对多关系的中间表的表名。
模型元数据选项
选项 说明
abstract 设置为True时模型是抽象父类
app_label 如果定义模型的应用不在INSTALLED_APPS中可以用该属性指定
db_table 模型使用的数据表名称
db_tablespace 模型使用的数据表空间
default_related_name 关联对象回指这个模型时默认使用的名称,默认为_set
get_latest_by 模型中可排序字段的名称。
managed 设置为True时,Django在迁移中创建数据表并在执行flush管理命令时把表移除
order_with_respect_to 标记对象为可排序的
ordering 对象的默认排序
permissions 创建对象时写入权限表的额外权限
default_permissions 默认为('add', 'change', 'delete')
unique_together 设定组合在一起时必须独一无二的字段名
index_together 设定一起建立索引的多个字段名
verbose_name 为对象设定人类可读的名称
verbose_name_plural 设定对象的复数名称

查询参考

按字段查找可以用的条件

  1. exact / iexact:精确匹配/忽略大小写的精确匹配查询
  2. contains / icontains / startswith / istartswith / endswith / iendswith:基于like的模糊查询
  3. in :集合运算
  4. gt / gte / lt / lte:大于/大于等于/小于/小于等于关系运算
  5. range:指定范围查询(SQL中的between…and…)
  6. year / month / day / week_day / hour / minute / second:查询时间日期
  7. isnull:查询空值(True)或非空值(False)
  8. search:基于全文索引的全文检索(一般很少使用)
  9. regex / iregex:基于正则表达式的模糊匹配查询

本文来自这个系列长期转载Python-100-Days ,本文观点不代表蓝洛水深立场,转载请联系原作者。

Like (0)
蓝洛水深的头像蓝洛水深管理员
Previous 2020年8月18日 上午12:19
Next 2020年8月21日 下午11:58

相关推荐

发表回复

Please Login to Comment
联系QQ
联系QQ
SHARE
TOP