Django对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite和Oracle,而且为这些数据库提供了统一的调用API,这些API统称为ORM框架。通过使用Django内置的ORM框架可以实现数据库连接和读写操作。
构建模型
ORM框架是一种程序技术,用于实现面向对象编程语言中不同类型系统的数据之间的转换。从效果上说,其实是创建了一个可在编程语言中使用的“虚拟对象数据库”,通过对虚拟对象数据库操作从而实现对目标数据库的操作,虚拟对象数据库与目标数据库是相互对应的。在Django中,虚拟对象数据库也称为模型。通过模型实现对目标数据库的读写操作,实现方法如下:
配置目标数据库信息
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# },
# mysql 的配置
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_database', # 你的数据库名
'USER': 'root', # 你的用户
'PASSWORD':'abcdef' , # 你的密码
'HOST': '192.168.43.205' , # 数据库所在IP,
'PORT': '3306' , # 端口
}
}
如果数据库不能远程,可参考mysql远程访问中的mysql命令改表法,能快速实现。
构建虚拟数据库
from django.db import models
# Create your models here.
class Type(models.Model):
id = models.IntegerField(primary_key=True)
type_name = models.CharField(max_length=20)
class Product(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=50)
weight = models.CharField(max_length=20)
size = models.CharField(max_length=100)
type = models.ForeignKey(Type, on_delete=models.CASCADE)
在上述例子中,我们创建了数据表index_product和index_type,而表字段是在模型中定义的,在模型Type和Product中定义的字段类型有整型和字符串类型,但在实际开发中,我们需要定义不同的数据类型来满足各种需求,因此Django划分了多种不同的数据类型:
Django提供的字段类型还会对数据进行正则处理和验证功能等,进一步完善了数据的严谨性。除了表字段类型之外,每个表字段还可以设置相应的参数,使得表字段更加完善。
虚拟数据库迁移到目标数据库
python manage.py makemigrations
python manage.py migrate
makemigrations指令用于将index所定义的模型生成0001_initial.py文件,该文件存放在index的migrations文件夹,打开查看0001_initial.py文件。
数据表间的关系
一个模型对应目标数据库的一个数据表,但我们知道,每个数据表之间是可以存在关联的,表与表之间有三种关系:一对一、一对多和多对多。
一对一关系
在模型中可以通过OneToOneField来构建数据表的一对一关系,代码如下:
class Performer(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
nationality = models.CharField(max_length=20)
masterprice = models.CharField(max_length=50)
class Performer_Info(models.Model):
id = models.IntegerField(primary_key=True)
performer = models.OneToOneField(Performer, on_delete=models.CASCADE) #一对一
birth = models.CharField(max_length=20)
elapse = models.CharField(max_length=20)
一对多关系
在模型中可以通过ForeignKey来构建数据表的一对多关系,代码如下:
class Program(models.Model):
id = models.IntegerField(primary_key=True)
performer = models.ForeignKey(Performer,on_delete=models.CASCADE)
name = models.CharField(max_length=20)
多对的关系
在模型中可以通过ManyToManyField来构建数据表多的对多关系,代码如下:
class Advertiser(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
performer = models.ManyToManyField(Performer)
进行数据迁移:
python manage.py makemigrations
python manage.py migrate
数据表的读写
数据库的读写操作主要对数据进行增、删、改、查。以的数据表index_type和index_product为例,分别在两个数据表中添加下面的数据。
为了更好地演示数据库的读写操作,在项目中使用shell模式(启动命令行和执行脚本)进行讲述,该模式主要为方便开发人员开发和调试程序。在PyCharm的Terminal下开启shell模式,输入python manage.py shell指令即可开启:
插入数据
下面在index_type中插入数据:
from index.models import *
t = Type(id=1,type_name='手机')
t.save()
t = Type(id=2,type_name='平板电脑')
t.save()
t = Type(id=3,type_name='智能穿戴')
t.save()
t = Type(id=4,type_name='通用配件')
t.save()
p = Product(id=1,name='荣耀V10',weight='172g',size='157.00*74.98*6.97mm',type_id=1)
p.save()
p = Product(id=2,name='HuaWEI nova2s',weight='169g',size='156.9*75.1*7.5mm',type_id=1)
p.save()
p = Product(id=3,name='荣耀Waterplay',weight='465g',size='248*173*7.8mm',type_id=2)
p.save()
p = Product(id=4,name='荣耀畅玩平板',weight='460g',size='9.8*159.8*7.95mm',type_id=2)
p.save()
p = Product(id=5,name='PORSCHE DESIGN',weight='64g',size='45*48.3*1.6mm',type_id=3)
p.save()
p = Product(id=6,name='华为运动手环',weight='21g',size='44*19.7*10.3mm',type_id=3)
p.save()
p = Product(id=7,name='荣耀移动电源1000mA',weight='210g',size='139*73.7*15.5mm',type_id=4)
p.save()
p = Product(id=8,name='荣耀体脂秤',weight='1850g',size='300*300*23.7mm',type_id=4)
p.save()
更新数据
删除数据
查询数据
from index.models import *
#------ 全表查询 ------------
# SQL:select * from index_product,
p = Product.objects.all()
p[1].name
#SQL: select * from index_product LIMIT 5,
p = Product.objects.all()[:5]
#SQL: select name from index_product,
p = Product.objects.values('name')
#------where 查询 ------------
#SQL: select * from index_product where id = 2,
p = Product.objects.get(id=2)
p.name
p = Product.objects.filter(id=2)
p[0].name
#------ and 查询 -----------
#SQL: select * from index_product where id = 9 and name='华为荣耀',
p = Product.objects.filter(name='华为荣耀',id=9)
#------ or 查询 -----------
#SQL: select * from index_product where id = 9 or name='华为荣耀',
from django.db.models import Q
p = Product.objects.filter(Q(name='华为荣耀')|Q(id=9))
# ------ count() ---------
#SQL:使用count方法统计查询数据的数据量
p = Product.objects.filter(name='荣耀V10').count
p
#------ distinct ------
# SQL: select distinct name from index_product where name ='荣耀V10'
p = Product.objects.values('name').filter(name='荣耀V10').distinct()
p
#------- order_by --------
# SQL: select id, name from index_product order by id,
p = Product.objects.order_by('-id','name')
#------- group by -------
select name, Sum(id) as 'id_sum' from index_product group by name order by null
from django.db.models import Sum, Count
p = Product.objects.values('name').annotate(Sum('id'))
print(p.query)
# ------ count() ---------
# select Count(id) as 'id_count' from index_product
p = Product.objects.aggregate(id_count=Count('id'))
多表查询
我们了解到数据表的读写操作,但仅仅局限在单个数据表的操作。在日常的开发中,常常需要对多个数据表同时进行数据查询。多个数据表查询需要数据表之间建立了表关系才得以实现。
一对多或一对一的表关系是通过外键实现关联的,而多表查询分为正向查询和反向查询。以模型Product和Type为例:
• 如果查询对象的主体是模型Type,要查询模型Type的数据,那么该查询称为正向查询。
• 如果查询对象的主体是模型Type,要通过模型Type查询模型Product的数据,那么该查询称为反向查询。
从上面的代码分析,因为正向查询的查询对象主体和查询的数据都来自于模型Type,因此正向查询在数据库中只执行了一次SQL查询。而反向查询通过t[0].product_set.values(‘name’)来获取模型Product的数据,因此反向查询执行了两次SQL查询,首先查询模型Type的数据,然后根据第一次查询的结果再查询与模型Product相互关联的数据。为了减少反向查询的查询次数,我们可以使用select_related方法实现,该方法只执行一次SQL查询就能达到反向查询的效果。select_related使用方法如下:
p = Product.objects.select_related('type').values('name','type_type_name')
print(p.query)
p = Product.objects.select_related('type').all()
print(p.query)
p = Product.objects.select_related('type').filter(id_gt=8)
print(p.query)
p = Product.objects.select_related('type').filter(type_type_name='手机').all()
p
参考文献:玩转Django 2.0/黄永祥著.-北京:清华大学出版社,2018