Django 2.0实战:博客系统2

创建项目

pip install Django~=1.11

mkdir typeidea,包含四个基本文件

关于requirements.txt有两点需要说明,一是有些团队可能会同时存在一个requirements_dev.txt文件,用来做开发环境的依赖项。二是在requirements.txt上面可以配置PyPI的源,如

-i http://pypi.doubanio.com/simple/

-e .    # 表示从当前setup.py中查找其他依赖项

创建项目源代码

django-admin startproject typeidea

这样我们的项目配置和源码就区分开了。之后,还会增加打包和自动化部署的相关配置。

接着,进入typeidea/typeidea目录

python manage.py runserver

基本配置

拆分settings以适应不同的运行环境

我们需要开发环境、测试环境和线上环境,如果只在一个文件写,维护起来十分麻烦。因此需要把这个settings.py拆成一个package(即文件夹),不同的配置分别定义为不同的模块(module)。

$ mkdir settings 

$ touch settings/__init__.py

$ mv settings.py settings/base.py

之后需要创建的profile(不同的配置文件)都是基于base模块的。

$ touch settings/develop.py  创建开发环境

修改时区和语言配置base.py

LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'

develop.py  其中 # NOQA 告诉PEP 8 规范检测工具不需要检测。 # flake8: NOQA为需要检测

from .base import *  # NOQA
DEBUG = True
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

还需要修改两个文件---manage.py和typeidea/wsgi.py

读取系统环境变量中TYPEIDEA_PROFILE来控制Django加载不同的settings文件

# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "typeidea.settings")
profile = os.environ.get('TYPEIDEA_PROFILE', 'develop')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "typeidea.settings.%s" % profile)

配置Git

通过git来进行版本管理

编写Model层的代码

对于内容或者说数据驱动的项目来说,设计好模型是成功的一半,因为后续的所有操作都是基于Model的。

其中User模型可以直接使用Django自带的。另外,需要关注其中一对多和多对多的关系。在大型项目设计中,常常需要借助一些工具,如UML、E-R图、思维导图等来帮助我们可视化地分析项目结构。

每个App应该是一个自组织的应用(所谓自组织,是指应用内部的所有逻辑都是相关联的,可以理解为是紧耦合的)。

这里把所有Model划分为三类:blog相关、配置相关和评论相关。

1、blog APP

创建新的分支:git checkout -b add-blog-app-model

$ cd typeidea/typeidea

$ python manage.py startapp blog  

blog/models.py

......

Model以及字段类型一起构成了ORM

2、编写config App 

用来配置相关的数据---侧边栏和友链

$ python manage.py startapp config

config/models.py

......

3、创建评论 App

评论可以是完全独立的模块,如果往大了做,可以作为独立的系统,比如:畅言、Disqus等产品。我们可以把它耦合到文章上,创建一个一对多的关系。当然,我们也可以做得松耦合一点,评论功能完全独立,只关系针对哪个页面(或URL)来评论。这样做的好处是,产品可以增加新的页面类型,比如友链页增加评论或者文章列表页增加评论,只关心URL,而不用关心要评论的对象是什么。

$ python manage.py startapp comment

comment/models.py

......

配置INSTALLED_APPS

settings/base.py

INSTALLED_APPS = [
    'blog',
    'config',
    'comment',
    
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

这里的列表顺序需要格外注意,Django会根据顺序挨个去这些APP中查找对应资源,这意味着如果资源路径和名称相同的话,前面的会覆盖掉后面的。

配置数据库

$ python manage.py makemigrations

$ python manage.py migrate

$ python manage.py dbshell  # 查看数据库
sqlite> .tables

提交代码

执行命令git commit

Model层:字段介绍

ORM(Object Relational Mapping,对象关系映射),就是把对象(类)映射到对应的数据库的表上。所以ORM就是代码层面对于数据库表和关系的一种抽象。

1、数值型字段

  • AutoField   int(11) 。 自增主键, Django Mode l 默认提供 , 可以被重写 。 它的完整定义是 id = models.AutoField(primary_key=True)。
  • BooleanField tinyint(1)。 布尔类型字段,一般用于记录状态标记 。
  • DecimalField decimal 。 开发对数据精度要求较高的业务时考虑使用 ,比如做支付相关、金融相关。 定义时,需要指定精确到多少位,比如 cash =models . DecimalField(max_digits=8, decimal_places=2 , default=0, verbose name= " 消费金额 ” )就是定义长度为 8 位、精度为 2 位的数字。 比方说,你想保存 666.66 这样的数字,那么你的 max_digits 就需要为 5, decimal_places 需要为 2。同时需要注意的是,在 Python 中也要使用 Decimal 类型来转换数据(from decimal import Decimal )。
  • IntegerField   int(11)。 它同 AutoField 一样,唯一的差别就是不自增 。
  • positiveintegerField 。 同IntergerField ,只包含正整数 。
  • SmallintegerField smallint 。 小整数时一般会用到 。
     

2、字符型

  • CharField   varchar 。 基础的 varchar 类型 。
  • URLField 。 继承自 CharField ,但是实现了对 URL 的特殊处理 。
  • UUIDField char(32 ) 。 除了在 PostgreSQL 中使用的是 uuid 类型外,在其他数据库中均是固定长度 char(32),用来存放生成的唯一 id。
  • EmailField 。 同URLField一样,它继承自 CharField, 多了对 E-mail 的特殊处理 。
  • FileField 。 同 URLField 一样,它继承自 CharField ,多了对文件的特殊处理 。 当你定义一个字段为 FileField 时,在 admin 部分展示时会自动生成一个可上传文件的按钮。
  • TextField longtext 。 一般用来存放大量文本内容,比如新闻正文、博客正文 。
  • ImageField 。 继承自 FileField ,用来处理图片相关的数据,在展示上会有不同 。
     

3、日期类型

  • DateField
  • DateTimeField
  • TimeField

4、关系类型

  • ForeignKey
  • OneToOneField
  • ManyToManyField

其中外键和一对一其实是一种,只是一对一在外键的字段上加了unique。而多对多会创建一个中间表,来进行多对多的关联。

提供了哪些参数

  • null 。 可以同 blank 对 比考虑,其中 null 用于设定在数据库层面是否允许为空 。
  • blank 。 针对业务层面,该值是否允许为空 。
  • choices 。 前面介绍过,配置字段的 choices 后,在 admin 页面上就可以看到对应的可选项展示 。
  • db_column 。 默认情况下,我们定义的 Field 就是对应数据库中的字段名称 ,通过这个参数可以指定 Model 中的某个字段对应数据库中的哪个字段 。
  • db_index。 索引配置。 对于业务上需要经常作为查询条件的字段,应该配置此项 。
  • default 。 默认值配置 。
  • editable 。 是否可编辑,默认是 True 。 如果不想将这个字段展示到页面上,可以配置为 False 。
  • error_messages 。 用来自定义字段值校验失败时的异常提示,它是字典格式 。 key 的可选项为null 、 blank 、 invalid 、invalid_choice 、 unique 和 unique_for_date 。
  • help_text 。 字段提示语,配置这一项后,在页面对应字段的下方会展示此配置 。
  • primary_key 。 主键,一个 Model 只允许设置一个字段为 primary_key 。
  • unique 。 唯一约束,当需要配置唯一值时,设置 unique=True ,设置此项后,不需要设置 db_index 。
  • unique for date 。 针对 date ( 日期)的联合约束,比如我们需要一天只能有一篇名为《学习 Dj ango 实战 》 的文章,那么可以在定义 title 字段时配置参数: unique_for_date ="created_time"。

Model层:QuerySet的使用

通过Django的Model操作数据库。在Model层中,Django通过给Model增加一个objects属性来提供数据操作的接口。

QuerySet支持链式操作,即执行一个对象中的方法之后得到的结果还是这个对象,这样可以接着执行对象上的其他方法。

1、支持链式调用的接口

  • all 接口 。 相当于 SELECT * FROM table_name 语句,用于查询所有数据。
  • filter 接口 。 顾名思义,根据条件过滤数据,常用的条件基本上是字段等于、不等于、大于、小于。 当然,还有其他的,比如能改成产生 LIKE 查询的 : Model.objects.filter(content_contains = ” 条件 ” ) 。
  • exclude 接口。同 filter ,只是相反的逻辑 。
  • reverse 接口。把 QuerySet 中的结果倒序排列 。
  • distinct 接口 。 用来进行去重查询 , 产生 SELECT DISTINCT 这样的 SQL 查询 。
  • none 接口 。 返回空的 QuerySet 。

2、不支持链式调用的接口

  • get接口。
  • create 接口
  • get_or_create 接口 。 根据条件查找, 如果没查找到, 就调用 create 创建 。
  • update_or_create 接口 。 同 get_or_create ,只是用来做更新操作 。
  • count 接口 。 用于返回 QuerySet 有多少条记录, 相当于 SELECT COUNT ( * ) FROM table_narne 。
  • latest 接口 。 用于返回最新的一条记录, 但是需要在 Model 的 Meta 中定义 : get_latest_by = <用来排序的字段〉。
  • earliest 接口 。 同上,返回最早的一条记录 。
  • first 接口 。 从当前 QuerySet 记录中获取第一条 。
  • last 接口 。 同上,获取最后一条。
  • exists 接口 。需要判断 QuerySet 是否有数据
  • bulk_create 接口 。 同 create ,用来批量创建记录 。
  • in_bulk 接口 。 批量查 询, 接收两个参数 id_list和filed_name 。
  • update 接口 。 用来根据条件批量更新记录
  • delete 接口 。 同 update ,这个接口是用来根据条件批量删除记录。
  • values 接口 。 当我们明确知道只需要返回某个字段的值
  • values_list 接口 。 同 values ,但是直接返回的是包含 tuple 的 QuerySet
     

3、进阶接口,用来提高性能的接口

  • defer接口 。 把不需要展示的字段做延迟加载 。
  • only 接口 。 同 defer接口 刚好相反,如果只想获取到所有的 title 记录,就可以使用only ,只获取 title 的内容 , 其他值在获取时会产生额外的查询 。
  • select_related 接口 。 这就是用来解决外键产生的 N+1 问题的方案 。
  • prefetch related 接口 。 针对多对多关系的数据,可 以通过这个接口来避免 N+1 查询 。
     

4、常用字段查询

  • contains :包含, 用来进行相似查询 。
  • icontains :同 contains ,只是忽略大小写 。
  • exact : 精确匹配 。
  • iexact :同 exact ,忽略大小写 。
  • in :指定某个集合 ,比如 Post.objects.filter(id_in=[1,2,3] )相当于 SELECT * FROM blog_post WHERE IN (1, 2, 3 ); 。
  • gt :大于某个值 。
  • gte : 大于等于某个值 。
  • lt :小于某个值 。
  • lte :小于等于某个值。
  • startswith :以某个字符串开头,与 contains 类似,只是会产生 LIKE ’ 〈关键词 〉毡 ’这样的 SQL。
  • istartswith :同 startswith ,忽略大小写 。
  • endswith :以某个字符串结尾 。
  • iendswith :同 endswith ,忽略大小写 。
  • range :范围查询,多用于时间范围

5、进阶查询,比如id=1 OR id=2这样的查询,用上面的基础查询就我无法满足

F表达式。常用来执行数据库层面的计算,从而避免出现竞争状态。比如需要处理文章的访问量用

post = Post.objects.get(id=1)
post.pv = post.pv + 1
post.save()

在多线程的情况下会出现问题。因为这里先读再写。通过F表达式可解决这个问题。这产生了SQL语句:UPDATE blog_post SET pv = pv+ 1 WHERE ID = 1。它在数据库层面执行原子性操作。

from django.db.models import F
post = Post.objects.get(id=1)
post.pv = F('pv') + 1
post.save()

Q表达式。用来解决前面提到的OR查询。

from django.db.models import Q
Post.objects.filter(Q(id=1) | Q(id=2))

Count。用来做聚合查询。

Sum。用来做合计

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值