Django 框架对数据库的操作
Django是🔥了多年的python web开发框架,在python界的火爆不输于Java界的Spring。与之类似的还有Flask,但是flask对python 3的支持度有点低,所以我还是选择使用Django。
温馨提示:Django中的D不发音,所以这个框架叫“粘钩”
Django与数据库的交互有点像JPA框架,严重的约定优于配置。国内搞Java开发的受阿里影响,基本都用mybatis,喜欢自己写灵活的SQL语句,而不喜欢依托规则。毕竟SQL几年前就学会了,可是要学比如JPA,还得特意去学其特性,烦!
模型
Django 应用创建好以后,数据模型都放在APP的models.py文件中。模型需要继承django.db.models.Model类,这样Django才能自动处理,为其生成表。比如:
from django.db import models
class MyMD(models.Model):
id = models.IntegerField
上面这个模型只定义了主键字段id。下面是一个稍微复杂点的模型:
class MyMd(models.Model):
id = models.IntegerField
shop_id = models.CharField(max_length=8, default='')
goods_id = models.CharField(max_length=30, default='')
file = models.FileField(max_length=200, blank=False, null=False)
created_at = models.DateTimeField('创建时间', auto_now_add=True, null=False, blank=False)
created_by = models.CharField(max_length=50, default='')
updated_at = models.DateTimeField('变更时间', auto_now=True, null=False, blank=False)
updated_by = models.CharField(max_length=50, default='')
last_updated_at = models.DateTimeField('时间戳', auto_now=True)
def __str__(self):
return self.image_name + self.file.name
class Meta:
db_table = "my_table"
indexes = [
models.Index(fields=['shop_id', 'goods_id'])
]
上面这个类加了更多字段,字段类型也丰富了,除了主键是整型以外,用的最多的当然是字符串models.CharField。models.CharField必须传入参数max_length。另外还有表示日期的models.DateTimeField类型字段,如果指定其为auto_now,则记录插入和保存的时候都会自动更新;如果指定为auto_now_add,则在插入的时候插入当前时间。这里还有一个字段是文件上传的models.FileField,当然它只记录文件或图片上传保存后的服务器路径。
这个模型最下面是一个Meta内部类,用于特殊配置,比如指定了这个模型生成的表名是my_table,否则会是app名加上模型名。另外还指定了一个联合索引,需要的话可以指定更多索引。
迁移
Django把根据模型生成数据映射文件的过程叫migrate,中文翻译过来是迁移,有点怪。 迁移很简单,直接使用命令(对,是命令,没有GUI操作):
python manage.py makemigrations my_app_name
这样会在my_app_name中生成migrate目录,里面就是映射文件。模型每次变更都会追加一个映射文件,所以第一次会是0001,第二次就是0002。
可以使用命令 python manage.py sqlmigrate my_app_name 0001
查看对应映射文件要执行的SQL语句。
映射文件并不只是用于生成SQL的,那样的话模型直接生成更好。前面提到的自动复制自动并不会写入SQL,而是在应用执行的时候,根据映射文件判断的。所以你在生成的SQL中看不到
CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
这种语句。
最后就是执行上面看到的SQL了,当然不用复制出来去跑一下,而是执行:
python manage.py migrate
你会看到数据库生成了很多莫名其妙的表,这是Django各种插件迁移的结果。其实替你生成表并不是Django的特性,很多框架和中间件都会这样。
读写
正如上面提到,Django对数据库的操作是基于规则的。比如已经有一个模型的实例m:
m = MyMd(...)
调用m.save()即刻插入数据库,并且m会被附上插入后的主键(当然mybatis也是这样)。如果m更新了,也是调用m.save()。
Django中的模型增改就是这样简单,复杂和舒服的是读取规则。比如要查询全部记录:
all_ = MyMd.objects.all()
要查询某个字段是“XXX”的记录的ID和名字:
XXXset = MyMd.objects.filter(shop_id = 'XXX').values('id', 'name')
如果你熟悉Java8的流式操作,是不是有点熟悉?
Django中的数据读取都是延迟执行的,也就是需要拿数据进行操作了,数据库查询才会进行。比如有另一个模型BlackList,记录的是MyMd的黑名单,我们想查询不在名单中的全部XXX记录,这样需要先查出来黑名单的id集合,用它去过滤模型:
bl = BlackList.objects.all().values('id') # 全部id
all_ = MyMd.objects.filter(Q(shop_id = 'XXX') & ~Q(id__in=bl)).values('id', 'name')
这里有几个要点:使用了Q语法,使用了否定~,使用了与操作&。关于它们更多的信息可以自行去谷歌上百度一下。
如果只有上面两句语句,并不产生任何的数据查询,因为它们的结果没有被使用。当遍历all_的时候,上面两句会生成一个大SQL:
select id, name from my_table where shop_id = 'XXX' and id not in (select id from blacklist) a
可以通过all_.query查看生成的sql。也可以引入connection查看:
from django.db import connection
print('查询数据库', connection.queries)
这样会打印所有已经执行过的SQL。
生产中是不鼓励使用外键的,而Django对外键设计做了大量优化,实在有点可惜 ```
