django - 用于多个模型的 Django 嵌套序列化程序,带有链式外键
问题描述
让我们以这 3 个简单的模型为例。一个城市可以有多个店铺,一个店铺可以有多个产品
模型.py
class City(models.Model):
name=models.CharField(max_length=300)
class Shop(models.Model):
name = models.CharField(max_length=300)
city = models.ForeignKey(City, related_name='related_city', on_delete=models.CASCADE)
class Product(models.Model):
name=models.CharField(max_length=300)
shop=models.ForeignKey(Shop, related_name='related_shop', on_delete=models.CASCADE)
序列化程序.py
class CitySerializer(serializers.ModelSerializer):
class Meta:
model = City
fields=['id','name']
class ShopSerializer(serializers.ModelSerializer):
related_shop = CitySerializer(many=True, read_only=True)
class Meta:
model = Shop
fields=['id','name','related_city']
class ProductSerializer(serializers.ModelSerializer):
related_shop = ShopSerializer(many=True, read_only=True)
class Meta:
model = Product
fields=['id','name','related_shop']
在views.py 的get_queryset() 中,我使用.select_related().all() 来获取外来对象。ProductSerializer 会给我所有的产品,并会获取 foreignKey 商店,我也会得到找到这个产品的商店的名称。
ShopSerializer 会以类似的方式给我所有商店的名称,以及可以找到这家商店的所有城市。
但是我怎样才能制作一个序列化程序,它会一次从所有 3 个表中检索?我想要的字段是: fields=['product_name','shop_name', 'city_name']
我知道,我将得到的那个列表会有重复,可以被认为是 1NF 或 2NF,与我作为数据库 3NF 的模型设计相反。但这就是我想要的查询。
我实际上正在考虑对我的数据库进行非规范化,所以我可以轻松实现这一点。
我的第二个问题是,将其非规范化为 1NF 并进行重复是否更好,以便减少这 3 个表之间“id”上的 CPU 密集型内部连接?我对此进行了很多研究,通常懒惰的答案是:尝试两种变体,基准测试,然后自己决定。
解决方案
您的问题将有不同的方法。一次从数据库中获取相关对象实际上并不依赖于序列化程序本身。这是在您的视图层中完成的,您可以在其中附加select_related('shop__city')
到您的查询集。通过附加它,您将在单个查询中同时在对象上预加载值shop
和shop.city
值。Product
序列化这些字段的一种简单方法是source
在序列化器字段中设置,如下所示:
class ProductSerializerV2(serializers.ModelSerializer):
shop_name = serializers.CharField(source='shop.name')
city_name = serializers.CharField(source='shop.city.name')
class Meta:
model = Product
fields = ['name', 'shop_name', 'city_name']
结论
根据上面的描述,下面的代码片段将只有一个对数据库的查询
p = Product.objects.select_related('shop__city').last()
print(ProductSerializerV2(p).data)
# {'name': 'product-z', 'shop_name': 'shop-z', 'city_name': 'z'} as a sample output
推荐阅读
- python - Pandas 中的额外条形图?
- php - 如果出现多个连字符,则从路由中获取变量
- python - Python:pandas groupby 到基于索引的字典
- c# - 使用 CsvHelper 从 CSV 文件中获取单元格值的问题
- php - 哪里没有工作
- java - 删除每个单词末尾的字母“e” Java
- c# - 如果权限在集合 A 中,如果不在集合 B 中,如何使用 LINQ 搜索权限
- curl - 在 curl 中使用 --local-port 选项时在 tcpdump 中获取不同的本地端口值
- sql - 在 Oracle 中生成具有 2 个日期之间时间间隔的行
- javascript - 加载器 div 中的 ASP.net GIF 即使正确调用也不播放