文章目录
1.表结构
类的方式定义表
-
编写类
from django.db import models class UserInfo(models.Model): name = models.CharField(max_length=16) age = models.IntegerField()
-
注册app
INSTALLED_APPS = [ # 'django.contrib.admin', # 'django.contrib.auth', # 'django.contrib.contenttypes', # 'django.contrib.sessions', # 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.app01.apps.App01Config', 'apps.app02.apps.App02Config', ]
1.1 常见字段和参数
1.1.1 字段
CharField 字符串型
SmallIntegerField 整型
IntegerField
BigIntegerField
DateField 时间
DateTimeField
BooleanField -> 其实数据库不支持真假,根据SmallIntegerField创造出来出来。 0 1
DecimalField -> 精确的小数 在钱的表示中使用这个字段
1.1.2 参数
name = models.CharField(verbose_name="姓名", max_length=16)
name = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈")
# 经常查询,速度快(MySQL,https://www.bilibili.com/video/BV15R4y1b7y9)
name = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈", null=True, blank=True, db_index=True) #索引
email = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈", null=True, blank=True, unique=True) #唯一
# blank和null的区别
# https://blog.youkuaiyun.com/qq_39253370/article/details/109717356
# 在数据库存储时只能是:sh、bj (上海、北京一般用于页面显示中文)
code = models.CharField(verbose_name="姓名", max_length=16, choices=(("sh", "上海"), ("bj", "北京")),default="sh")
# 不用 max_length=16
count = models.IntegerField(verbose_name="数量", default=1, null=True, blank=True, unique=True)
code = models.IntegerField(verbose_name="性别",choices=((1, "男"), (2, "女")),default=1)
register_date = models.DateField(verbose_name="注册时间", auto_now=True)
amount = models.DecimalField(verbose_name="余额", max_digits=10, decimal_places=2)
示例:
from django.db import models
class UserInfo(models.Model):
name = models.CharField(verbose_name="姓名", max_length=16, db_index=True)
age = models.PositiveIntegerField(verbose_name="年龄")
email = models.CharField(verbose_name="邮箱", max_length=128, unique=True)
amount = models.DecimalField(verbose_name="余额", max_digits=10, decimal_places=2, default=0)
register_date = models.DateField(verbose_name="注册时间", auto_now=True)
class Goods(models.Model):
title = models.CharField(verbose_name="标题", max_length=32)
# detail = models.CharField(verbose_name="详细信息", max_length=255)
detail = models.TextField(verbose_name="详细信息")
price = models.PositiveIntegerField(verbose_name="价格")
count = models.PositiveBigIntegerField(verbose_name="库存", default=0)
1.2 表关系
- 单表
- 一对多
- 多对多
- 一对一
2.数据操作
2.1 连接 注册
编写ORM操作的步骤:
-
settings.py,连接数据库
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }
-
settings.py,注册app
INSTALLED_APP = [ ... "app01.apps.App01Config" ]
2.2 编写类与执行 映射
-
编写models.类
class UserInfo(models.Model): .... .....
-
执行命令
python manage.py makemigrations # 找到所有已注册的app中的models.py中的类读取 -> migrations配置 python manage.py migrate # 读取已注册的app下的migrations配置 -> SQL语句 -> 同步数据库
2.3 连接数据库
sqlites:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'xxxxxxxx', # 数据库名字
'USER': 'root',
'PASSWORD': 'root123',
'HOST': '127.0.0.1', # ip
'PORT': 3306,
}
}
安装第三方组件
-
pymysql
pip install pymysql
项目根目录/项目名目录/__init__.py import pymysql pymysql.install_as_MySQLdb()
-
mysqlclient
pip install mysqlclient
电脑上先提前安装MySQL。
3.连接池
django默认内置没有数据库连接池 。
pymysql -> 操作数据库
DBUtils -> 连接池
https://pypi.org/project/django-db-connection-pool/
pip install django-db-connection-pool
DATABASES = {
"default": {
'ENGINE': 'dj_db_conn_pool.backends.mysql',
'NAME': 'day04', # 数据库名字
'USER': 'root',
'PASSWORD': 'root123',
'HOST': '127.0.0.1', # ip
'PORT': 3306,
'POOL_OPTIONS': {
'POOL_SIZE': 10, # 最小
'MAX_OVERFLOW': 10, # 在最小的基础上,还可以增加10个,即:最大20个。
'RECYCLE': 24 * 60 * 60, # 连接可以被重复用多久,超过会重新创建,-1表示永久。
'TIMEOUT':30, # 池中没有连接最多等待的时间。
}
}
}
注意:组件django-db-connection-pool
不是特别厉害。拿了另外一个支持SQLAchemy数据库连接池的组件。
4.数据表操作
4.1 单表操作
单表增删改查:
关键字:
- 增加:create
- 删除:delete
- 更新:update
- 条件:filter
- 查看部分所有和单个:all() first
- query:查看对应的sql语句
举例练习:
class Role(models.Model):
title = models.CharField(verbose_name='标题',max_length=32)
od = models.IntegerField(verbose_name="排序")
def __str__(self):
return "{}-{}".format(self.title,self.od)
新增行:
obj1 = models.Role.objects.create(title='alex',od=1)
obj2 = models.Role.objects.create(**{"title":"管理员","od":2})
models.Role.objects.create(title='lcy',od=8)
models.Role.objects.create(title='lll',od=11)
obj = models.Role(title='mmm',od=12)
obj.od=11
obj.save()
删除与更改:
obj = models.Role.objects.filter(title='alex').delete()
print(obj)
obj1 = models.Role.objects.all().update(od=99,title='管理员')
models.Role.objects.filter(id=3).update(**{"title":'mm','od':22})
# 可以通过关键字传参或者传一个字典
条件查询:
v2 = models.Role.objects.filter(od__lt=99) #双下划线加条件的用法
v2 = models.Role.objects.filter(od__in=[8,11,3])
v2 = models.Role.objects.filter(title__contains='y')
v2 = models.Role.objects.filter(title__startswith='l')
v2 = models.Role.objects.filter(title__isnull=False)
v2 = models.Role.objects.exclude(id=5).filter(od=11) # 表示不等于 出去id=5的,就是不等于5
print(v2.query)
for obj in v2:
print(obj)
values和values_list
v4 = models.Role.objects.filter(id__gt=2).values('id','title') #获取到的是列表
#print(v4.queryset)
print(v4)
v5 = models.Role.objects.filter(id__gt=2).values_list('id','title') #获取到 的是元组
print(v5)
v6 = models.Role.objects.filter(id__gt=2).values('id','title') #.first()
print(v6.query) # 这样可以得到生成的sql语句,但是加上first就不可以了,那样得到的是具体的值
print(v6)
v6 = models.Role.objects.filter(id__gt=2).values('id', 'title').first()
print(v6.query)
print(v6)
- 排序
v6 = models.Role.objects.filter(od__gt=22).exists() # 查看是否存在
print(v6)
v7 = models.Role.objects.order_by('-id','od') # 排序 加-代表是desc方式,如果不加代表asc方式
print(v7)
4.2 一对多
一对多联表查询:
class Depart(models.Model):
title = models.CharField(max_length=32)
class Admin(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
depart = models.ForeignKey(to="Depart",on_delete=models.CASCADE)
映射到表内是这样的:
可以看到,虽然class内定义的是depart,但是反应在表内的结果确实depart_id,直接通过depart_id是能够对应到depart表内的id列的。
以上两个为部门表和人员表
添加数据:
models.Depart.objects.create(title='销售')
models.Depart.objects.create(title='开发')
models.Depart.objects.create(title='财务')
#虽然这里写的是depart,但是因为外键的缘故,生成出来就是depart_id
models.Admin.objects.create(name='lcy',pwd='123',depart_id=2)
models.Admin.objects.create(name='lll',pwd='234',depart_id=1)
models.Admin.objects.create(name='武沛齐',pwd='12345',depart_id=3)
# 以上方式最简便,因为默认两个表通过外键相连的
obj = models.Depart.objects.filter(id=2).first()
models.Admin.objects.create(name='lcyyy',pwd='123',depart=obj)
models.Admin.objects.create(name='lcy12',pwd='123',depart_id=obj.id)
# 以上三种方式均能实现添加id并且与depart相连
查询:
# 通过depart_id可以连接到本表内的depart_id字段,通过depart__title可以连接到depart表内的title字段,其余字段相同
v6 = models.Admin.objects.filter(depart__title='开发').all().values()
print(v6)
# 因为已经联表了,所以可以通过depart__字段 连表和条件
v6 = models.Admin.objects.filter(depart__title='销售').delete()
print(v6.query)
v7 = models.Admin.objects.filter(depart__title='销售')
print(v7.query)
v1 = models.Admin.objects.filter(id__gt=0)
for obj in v1:
print(obj.id,obj.name,obj.pwd,obj.depart_id)
v2 = models.Admin.objects.filter(id__gt=0).select_related("depart")
for obj in v2:
print(obj.name, obj.pwd, obj.id, obj.depart_id, obj.depart.title)
v3 = models.Admin.objects.filter(id__gt=0).values('id','name','pwd','depart_id','depart__title')
print(v3)
4.3 多对多
class Boy(models.Model):
name = models.CharField(max_length=10,db_index=True)
class Girl(models.Model):
name = models.CharField(max_length=10,db_index=True)
class B2G(models.Model):
bid = models.ForeignKey(verbose_name="男生id",to='Boy',to_field='id',null=True,on_delete=models.CASCADE)
gid = models.ForeignKey(verbose_name='女生id',to='Girl',to_field='id',null=True,on_delete=models.CASCADE)
address = models.CharField(verbose_name='地点',max_length=32,null=True)
- 添加数据 与单次添加多个数据
models.Boy.objects.create(name='宝强')
models.Boy.objects.create(name='羽凡')
models.Boy.objects.create(name='乃亮')
models.Girl.objects.create(name='马蓉')
models.Girl.objects.create(name='小路')
models.Girl.objects.create(name='百合')
models.Girl.objects.bulk_create(
objs = [models.Girl(name='苍井空'),models.Girl(name='椎名由奈'),models.Girl(name='神波多一花')],
batch_size=3,
)
models.B2G.objects.create(bid_id=1,gid_id=1,address='bj')
models.B2G.objects.bulk_create(
objs = [models.B2G(bid_id=1,gid_id=3,address='sh'),models.B2G(bid_id=2,gid_id=8,address='jan'),models.B2G(bid_id=3,gid_id=9,address='tj'),],
batch_size = 3,
)
- 查询数据
v1 = models.B2G.objects.filter(bid__name='宝强').select_related('gid')
# 因为连表了,所以可以执行联查
print(v1.query)
# SELECT `asserts_b2g`.`id`, `asserts_b2g`.`bid_id`, `asserts_b2g`.`gid_id`, `asserts_b2g`.`address`, `asserts_girl`.`id`, `asserts_girl`.`name` FROM `asserts_b2g` INNER JOIN `asserts_boy` ON (`asserts_b2g`.`bid_id` = `asserts_boy`.`id`) LEFT OUTER JOIN `asserts_girl` ON (`asserts_b2g`.`gid_id` = `asserts_girl`.`id`) WHERE `asserts_boy`.`name` = 宝强
for v in v1:
print(v.id,v.address,v.bid.name,v.gid.name)
# 与一对多相同,可以通过双下划线实现取出其他表中的字段
v2 = models.B2G.objects.filter(bid__name='宝强').values('bid__name','gid__name','address')
print(v2)
v3 = models.B2G.objects.filter(gid__name='神波多一花').values('bid__name','gid__name','address')
print(v3)
4.4 一对一
class UserInfo(models.Model):
name = models.CharField(max_length=32,db_index=True)
pwd = models.CharField(max_length=32)
class Blog(models.Model):
user = models.OneToOneField(max_length=32,to='UserInfo',on_delete=models.CASCADE)
blog = models.CharField(verbose_name="博客地址",max_length=255)
summary = models.CharField(verbose_name="简介",max_length=128)
- 添加数据
models.UserInfo.objects.create(name='武沛齐',pwd='12345')
models.UserInfo.objects.create(name='lcy',pwd='12345')
models.Blog.objects.create(blog='xxxx1',summary='mmmmm',user_id=1)
#models.Blog.objects.create(blog='xxx2',summary='nnnn',user_id=2)
user_object = models.UserInfo.objects.filter(name='lcy').first()
models.Blog.objects.create(blog='yyyy1',summary='nnnnn',user=user_object)
查询
user_object = models.UserInfo.objects.filter(name='lcy').select_related('blog').first()
print(user_object.id,user_object.name,user_object.pwd,user_object.blog.blog,user_object.blog.summary)
blog_object = models.Blog.objects.filter(id=1).select_related('user').first()
print(blog_object.blog,blog_object.summary,blog_object.user.name,blog_object.user.pwd)