django 通过外键操作ORM
1.在模型层新建数据表
class Country(models.Model): name = models.CharField(max_length=100) class Ctudent(models.Model): name = models.CharField(max_length=100) grade = models.PositiveIntegerField() country =models.ForeignKey(Country,on_delete=models.PROTECT)
导入数据:
from sales.models import *
c1 = Country.objects.create(name='中国')
c2 = Country.objects.create(name='美国')
c3 = Country.objects.create(name='法国')
Ctudent.objects.create(name='白月', grade=1, country=c1)
Ctudent.objects.create(name='黑羽', grade=2, country=c1)
Ctudent.objects.create(name='大罗', grade=1, country=c1)
Ctudent.objects.create(name='真佛', grade=2, country=c1)
Ctudent.objects.create(name='Mike', grade=1, country=c2)
Ctudent.objects.create(name='Gus', grade=1, country=c2)
Ctudent.objects.create(name='White', grade=2, country=c2)
Ctudent.objects.create(name='White', grade=2, country=c2)
Ctudent.objects.create(name='Napolen', grade=2, country=c3)
查询出学生名字为白月的所属国家
>>> s1 =Ctudent.objects.get(name='白月') >>> s1.country.name
查询学生表里面一年级的学生
>>> Ctudent.objects.filter(grade=1).values()
查询出一年级的中国学生
>>> Ctudent.objects.filter(grade=1,country__name="中国").values()
指定字段显示查询一年级的中国学生
>>> Ctudent.objects.filter(grade=1,country__name="中国").values("name",'country__name') <QuerySet [{'name': '白月', 'country__name': '中国'}, {'name': '大罗', 'country__name': '中国'}]>
给字段取别名
使用 annotate 方法
>>> Ctudent.objects.annotate(countryname=F('country__name'),studentname=F('name')).filter(grade=1,countryname="中国").values("studentname",'countryname') <QuerySet [{'countryname': '中国', 'studentname': '白月'}, {'countryname': '中国', 'sname': '大罗'}]>
反向访问:
通过 表Model名转化为小写
,后面加上一个 _set
来获取所有的反向外键关联对象
>>> cn.ctudent_set.all()
第二种实现反向访问的方法:
在定义Model的时候,外键字段使用 related_name
参数,像这样
class Country(models.Model): name = models.CharField(max_length=100) class Ctudent(models.Model): name = models.CharField(max_length=100) grade = models.PositiveIntegerField() country =models.ForeignKey(Country,on_delete=models.PROTECT ,related_name='ctudent')
>>> cn = Country.objects.get(name='中国') >>> cn.ctudent.all()
反向过滤:
获得一年级学生的国家名
>>> Country.objects.filter(ctudent__grade=1).values()
去重
使用 .distinct()
去重
>>> Country.objects.filter(ctudent__grade=1).values().distinct() <QuerySet [{'id': 1, 'name': '中国'}, {'id': 2, 'name': '美国'}]>
数据库事务:
场景:例如我们需要在一次操作找那个添加订单的操作,但是添加订单需要一般需要有订单表和商品订单表,这样我们添加一张订单的时候就需要执行两次数据库的操作,假如第一涨表添加成功时,请求又来了,所以又要执行一次添加请求操作,这样会让第二张表的数据丢失。为此我们需要引入数据库事务来进行控制,当第一张表添加后又来一次新的请求。当订单添加不成功时,数据库会有回滚事务。
django引入 with transaction.atomic() 来声明事务类型
def addorder(request): info = request.params['data'] # 从请求消息中 获取要添加订单的信息 # 并且插入到数据库中 with transaction.atomic(): new_order = Order.objects.create(name=info['name'] , customer_id=info['customerid']) batch = [OrderMedicine(order_id=new_order.id,medicine_id=mid,amount=1) for mid in info['medicineids']] OrderMedicine.objects.bulk_create(batch) return JsonResponse({'ret': 0,'id':new_order.id})
with transaction.atomic()
下面 缩进部分的代码,对数据库的操作,就都是在 一个事务
中进行了。
如果其中有任何一步数据操作失败了, 前面的操作都会回滚。
这就可以防止出现 前面的 Order表记录插入成功, 而后面的 订单药品 记录插入失败而导致的数据不一致现象。
大家可以发现 插入 OrderMedicine 表中的数据 可能有很多条, 如果我们循环用 ```py OrderMedicine.objects.create(order_id=new_order.id,medicine_id=mid,amount=1) ``` 插入的话, 循环几次, 就会执行 几次SQL语句 插入的 数据库操作 这样性能不高。
我们可以把多条数据的插入,放在一个SQL语句中完成, 这样会大大提高性能。