Task 10 原始数据库查询
虽然我们前面略微带过了数据库语句操作的部分,不过并不充分。Django中一共有3大使用原生sql查询的api, 分别是:
- Queryset.raw()
- Queryset.extra() (没用,过)
- django.db.connection 数据库连接对象
先说Queryset.raw, 用法如下:
#直接在raw字段中写入数据库查询语句
m = PlayerEntity.objects.raw('SELECT ******')
这里m是返回的不再是QuerySet 对象, 而是RawQuerySet对象。
QuerySet 与 RawQueryset本身都可以看作是查询结果的迭代器,也就是说可以转为list的对象, 而且迭代的值都是我们的PlayEntity(或者你自己的model类), 可以从类中直接调用一条PlayEntity数据。不同的是,RawQueryset 没有values的接口将参数序列化为字典的接口。虽然,再render的local() 调用下没什么区别,不过直接从控制台获得信息稍加麻烦
此外RawQuerySet的查询结果必须包含主键保证记录的不通过(毕竟是Set 噗),所以查询时一定要带上主键
限制: 查询的字段必须是模型中声明的字段
而且每次查询结果为定义的模型类,即全数据获取,无法自定义浪费大量空间
其次了解下QuerySet.extra() 官方文档扫了一遍没找到,那就直接开冲。
# 先看参数,看参数我们就能搞个大概了
def extra(
self,
select=None, * select的属性名
where=None, * 判断条件
params=None,
tables=None, * 表明
order_by=None, * 排序and排序顺序
select_params=None,
):
# 这里所有的参数均以元组/数组传参。
extra返回的是QuerySet类型,感觉和raw好不了多少甚至一样拉。。。还是返回的整个类么,与上面raw的缺点没有变化。有点我个人感觉也没啥,(怪不得没文档) 原来可以用raw取代。
优点: 条理使用数组/元组更清晰
缺点: 容易搞蒙 + raw的所有
django.db.connections
创建一个连接数据库的对象(connection) 可以通过这个对象获取curson对象,再通过cursor的execute,fetchall, rowcount等方法执行原生的SQL获取结果
拓展,cursor是平时用pymysql最常见的游标操作器,需要自行学习,返回类型为元组
from django.db import connection
ursor = connection.cursor()
cursor.execute('Select * from player_Info')
k = cursor.fetchmany(2)
k
((1, 'Son_Bitch', 26, 38.7, None),(2, 'MyLover', 23, 14.4, None))
Task 10.5 models.Manager过滤覆写
我们直接找models.Manager()源码的时候发现只有一句pass。 为了完成我们的过滤或是其他的筛选条件,我们可以通过继承覆写的方式给我们的objects赋值或是做过滤器
# models.py
class Game_Filter(models.Manage):
# 定义我们自己想要的方法,也可以覆写(我这里是获取已上架(代预售和已发售)的过滤器)
def get_onsailgame(self):
return super().get_queryset().filter(status__gte = 0)
class SomeEntity(models.Model):
...
...
objects = Game_Filter()
# views.py
def try_filter():
game = Gammer.objects.get_onsailgame().values()
print(game)
# Python Console
from tryNew.views import try_filter
try_filter() # 这里我测试了,确实拿到过滤的结果了
一个简单的以status做过滤(status >=1)的过滤器就完成了。当然,如果你想在所有欲地方,如后台等视觉上均过滤不要的数据,覆写的方法(Game_Filter) 改成 get_queryset即可
过滤的方法把上面学的F, Q用起来~~
Task 11模型类的关联关系
(题外话:讲到模型关系,我就想到我们当时学的ER 和EER模型了。怎么说呢,老师讲的挺一般的导致我对数据库也没深挖下去的乐趣了)
模型与模型的对应关系:
https://www.cnblogs.com/chichung/p/9905835.html
- 一对一关系。 (不能双发一对一,不然合并不就行了么)
- 一对多关系
- 多对多关系
工具:Powerdesigner, 在大二下/数据库/其他/Powerdesigner
建立关系,我们需要进行对Entity进行其他Entity的引用,借用models的接口完成关系映射
eg. 这是一个我完善过的一个Game list表单
#
class GamePlant(models.Model):
# 主要是Pc Ns Xbox Ps
game_plant = models.CharField(verbose_name="平台名称", max_length=30, primary_key=True)
start_time = models.DateField(verbose_name="成立时间", null=True, blank=True)
suppoert_chinese = models.IntegerField(verbose_name='支持情况', choices=((0, "不支持国区"), (1, "支持国区")), default=1)
def __str__(self):
return self.game_plant
class Meta:
db_table = 'games_plant'
verbose_name = "游戏平台"
verbose_name_plural = "游戏平台"
class GameMaker(models.Model):
gamer_name = models.CharField(verbose_name='开发团队', max_length=100, null=False, blank=False, primary_key=True)
gamer_location = models.CharField(verbose_name='团队位置', max_length=100, null=True, blank=True)
gamer_num = models.IntegerField(verbose_name='团队人数', null=True, blank=True)
def __str__(self):
return self.gamer_name
class Meta:
db_table = 'games_gamer'
verbose_name = "游戏厂商"
verbose_name_plural = "游戏厂商"
# class Gammer(Game_Filter)
class Gammer(models.Model):
name = models.CharField(verbose_name='游戏名称', max_length=50, null=False, blank=False)
onsail_time = models.CharField(verbose_name='上市日期', max_length=15, default='敬请期待')
price = models.IntegerField(verbose_name='价格', default=99999)
image = models.ImageField(verbose_name='游戏封面', null=True, blank=True)
author = models.ForeignKey(GameMaker, on_delete= models.CASCADE)
# 这里不应该是外键一对多,而应该是多对多
plantform = models.ManyToManyField(GamePlant)
status = models.IntegerField(choices=((0, '未开启预购'), (1, '开启预购'), (2, '正式发售')), default=0)
# 显性的创建查询结果集
objects = models.Manager()
def __str__(self):
return self.name
class Meta:
db_table = 'games_info'
verbose_name = '游戏之日'
verbose_name_plural = verbose_name
这里面虽然没有一对一,但是因为实际情况确实比较少我就没搞。我把数据库中存放的表的状态给你拿出来:
我把关系列表给搞出来了, 很明显n…n在Django的接口使用两个1…n来搞定的,1…n 是很轻松的搞定的,所以说是看出来了Django的关系映射确实是不容小视。API的使用直接看上面的代码和教程即可,这里只是澄清多对多使用两个1对多的关系实现,就够了