django2.0---外键关联的正向查询与反向查询探讨


发布时间:2019-04-08 13:22    作者: Uncle Hui   已过去:1 年,3 月   阅读总量:726 已被赞:0


大家使用 Django 创建模型的时候一定会经常使用 ForeignKey 来创建两个表格之间多对一的外键关系,例如B中有一个 models.ForeignKey(A) 。而当我们需要反向查询 A 中某个具体实例所关联的 B 时,可能会用到 A.B_set.all() 或 B.objects.filter(A) 这两种不同的方法。为了弄清楚外键关联的时候,正反向查询问题,我们先建立两个模型,然后给每个模型都加入部分数据,做好这些准备工作后,我们就来看看如何理解正反查询问题.

模型:

class Person(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    tel = models.CharField(max_length=64)
 上面这个模型存储人物信息,下面这个模型为车辆信息,建好这两个表,迁移数据,并加入测试数据

class Car(models.Model):
    owner = models.ForeignKey(Person,on_delete=models.DO_NOTHING)
    name = models.CharField(max_length=64)
    price = models.FloatField()
首先我们来看看正向查询,所谓正向查询就是由分表去查询主表的信息,具体到这里就是由Car表去查询Person表,查询方式就是通过外键关联的字段去查询,这里就是owner字段,例如我们查询车辆表里ID为1的这辆车的车主信息可以这样:

#正向查询,通过车辆找到车主(子表查主表)
def wj(request):
    car = Car.objects.get(id=1)
    #查询车主信息
    print(car.owner)
    #分别获取相关具体信息,获取车主姓名,电话,年龄
    print((car.owner.name))
    print((car.owner.tel))
    print((car.owner.age))
    return HttpResponse(11111111111111111)
 反向查询:所谓反向查询就是通过主表去差分别,通过没有设置models.ForeignKey这个字段的表去查于之关联的表的信息,我们有三种方式来实现:

第一种,通过:变量.子表名(小写)._set方法实现

例如:

#反向查询,通过车主找到他的全部车(主表查子表)
def fx(request):
    T = Person.objects.get(id=1)
    # 查询此人有多少车
    # 方式一:
    # Django默认每个主表对象都有一个外键的属性
    # 可以通过它来查询所有属于主表的子表信息
    # 查询方式:对象.子表名的小写_set()
    # 返回值为一个queryset对象
    #print( T.car_set.all())
这样就可以拿到信息了,值得说明的地方,本方式只能是在外键中未设置related_name属性时候使用,一旦设置了,上面的方法就不能使用了。

第二种,通过设置related_name属性实现查询

要使用本方法,首先要在模型中,关联外键的字段里,加入related_name方法,具体模型修改如下:

class Car(models.Model):
    owner = models.ForeignKey(Person, related_name='cars',on_delete=models.DO_NOTHING)
    #owner = models.ForeignKey(Person,on_delete=models.DO_NOTHING)
    name = models.CharField(max_length=64)
    price = models.FloatField()
 设置好后,饿哦们就可以这样来通过车主来获取车辆信息了:

def fx(request):
    T = Person.objects.get(id=1)
   # 方式二:
   # 通过在外键中设置related_name属性值既可
   print(T.cars.all())
 cars,就是我们在 related_name='cars',设置的字段名字。

第三种,通过@property装饰器在model中预定义方法实现

我们将主表修改一下:

class Person(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    tel = models.CharField(max_length=64)
    @property
    #获取全部车辆信息
    def all_cars(self):
        return self.cars.all()
    @property
    #获取人物具体信息
    def info(self):
        return '%s %s' % (self.name, self.tel)
 现在我们可以这样来查询了,

def fx(request):
    T = Person.objects.get(id=1)
    # 查询此人有多少车
    # 方式三:
    # 通过@property装饰器在model中预定义方法实现
    print(T.all_cars)
    print(T.info)
    return HttpResponse(2222222222)
 我们就通过调用定义的类的方法就可以实现相关查询了。当然,如果你使用的是方法一定义的,在 

@property
    #获取全部车辆信息
    def all_cars(self):
        return self.cars.all()
 这里就应该使用self.car_set.all() 这种方式来获取返回值了。

最后我们一起来温习下python的@property,我主要参考了梁雪峰的文章,

@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。

点赞

0




登陆后方可评论