Django入门学习--模型与数据库(models)

  Django对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite和Oracle,而且为这些数据库提供了统一的调用API,这些API统称为ORM框架。通过使用Django内置的ORM框架可以实现数据库连接和读写操作。

构建模型

ORM框架是一种程序技术,用于实现面向对象编程语言中不同类型系统的数据之间的转换。从效果上说,其实是创建了一个可在编程语言中使用的“虚拟对象数据库”,通过对虚拟对象数据库操作从而实现对目标数据库的操作,虚拟对象数据库与目标数据库是相互对应的。在Django中,虚拟对象数据库也称为模型。通过模型实现对目标数据库的读写操作,实现方法如下:

配置目标数据库信息

# __init__.py 中添加
 import pymysql
 pymysql.install_as_MySQLdb()

# 点击保存连接,进入到base.py 注释掉base.py 中的
#if version < (1, 3, 13):
#    raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)
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划分了多种不同的数据类型:
image.png
Django提供的字段类型还会对数据进行正则处理和验证功能等,进一步完善了数据的严谨性。除了表字段类型之外,每个表字段还可以设置相应的参数,使得表字段更加完善。
image.png

虚拟数据库迁移到目标数据库

python manage.py makemigrations

python manage.py migrate

makemigrations指令用于将index所定义的模型生成0001_initial.py文件,该文件存放在index的migrations文件夹,打开查看0001_initial.py文件。
image.png

image.png

数据表间的关系

一个模型对应目标数据库的一个数据表,但我们知道,每个数据表之间是可以存在关联的,表与表之间有三种关系:一对一、一对多和多对多。

一对一关系

在模型中可以通过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

image.png

数据表的读写

数据库的读写操作主要对数据进行增、删、改、查。以的数据表index_type和index_product为例,分别在两个数据表中添加下面的数据。
image.png
image.png
 为了更好地演示数据库的读写操作,在项目中使用shell模式(启动命令行和执行脚本)进行讲述,该模式主要为方便开发人员开发和调试程序。在PyCharm的Terminal下开启shell模式,输入python manage.py shell指令即可开启:
image.png

插入数据

下面在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()

更新数据

image.png

删除数据

image.png

查询数据

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'))

image.png

多表查询

我们了解到数据表的读写操作,但仅仅局限在单个数据表的操作。在日常的开发中,常常需要对多个数据表同时进行数据查询。多个数据表查询需要数据表之间建立了表关系才得以实现。
一对多或一对一的表关系是通过外键实现关联的,而多表查询分为正向查询和反向查询。以模型Product和Type为例:
• 如果查询对象的主体是模型Type,要查询模型Type的数据,那么该查询称为正向查询。
• 如果查询对象的主体是模型Type,要通过模型Type查询模型Product的数据,那么该查询称为反向查询。
image.png
从上面的代码分析,因为正向查询的查询对象主体和查询的数据都来自于模型Type,因此正向查询在数据库中只执行了一次SQL查询。而反向查询通过t[0].product_set.values('name')来获取模型Product的数据,因此反向查询执行了两次SQL查询,首先查询模型Type的数据,然后根据第一次查询的结果再查询与模型Product相互关联的数据。为了减少反向查询的查询次数,我们可以使用select_related方法实现,该方法只执行一次SQL查询就能达到反向查询的效果。select_related使用方法如下:
image.png

p = Product.objects.select_related('type').values('name','type_type_name')
print(p.query)

image.png

p = Product.objects.select_related('type').all()
print(p.query)

image.png

p = Product.objects.select_related('type').filter(id_gt=8)
print(p.query)

image.png

p = Product.objects.select_related('type').filter(type_type_name='手机').all()
p



参考文献:玩转Django 2.0/黄永祥著.-北京:清华大学出版社,2018

原文地址:https://www.cnblogs.com/sinlearn/p/12865286.html