Django基模型创建对象时按字段自动分配对应代理类的实现问询
Django 基于字段自动映射代理模型实现方案
方案a:先创建基类实例,再转换为对应代理类
这是你指定优先适配的方案,实现步骤如下:
- 为基类添加代理类映射关系和转换方法
- 为每个代理类自定义管理器,实现自动按物种过滤
完整实现代码
from django.db import models class Animal(models.Model): # 物种和对应代理类的映射表 SPECIES_PROXY_MAPPING = { "cat": "Cat", "dog": "Dog" } species = models.CharField(max_length=32) def to_proxy_instance(self): """将当前基类实例转换为对应代理类实例""" proxy_class = self.SPECIES_PROXY_MAPPING.get(self.species) # 兼容字符串类名引用,避免类定义顺序问题 if isinstance(proxy_class, str): proxy_class = globals()[proxy_class] if not proxy_class or isinstance(self, proxy_class): return self # 复制实例状态,不需要重复查询数据库 proxy_instance = proxy_class() proxy_instance.__dict__ = self.__dict__.copy() return proxy_instance # 自定义代理类管理器,自动过滤对应物种 class CatManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(species="cat") class Cat(Animal): class Meta: proxy = True objects = CatManager() class DogManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(species="dog") class Dog(Animal): class Meta: proxy = True objects = DogManager()
使用示例
# 先创建基类实例 cat_base = Animal.objects.create(species="cat") dog_base = Animal.objects.create(species="dog") # 转换为对应代理类实例 cat = cat_base.to_proxy_instance() # 类型为Cat dog = dog_base.to_proxy_instance() # 类型为Dog # 验证查询效果 Animal.objects.all() # 返回所有Animal实例的查询集 Cat.objects.all() # 返回仅包含species为cat的实例查询集 Dog.objects.all() # 返回仅包含species为dog的实例查询集
可选优化:如果需要Animal.objects查询结果直接返回代理实例,可自定义基类管理器,在返回查询集后批量调用to_proxy_instance方法转换即可。
方案b:创建对象时直接生成对应代理类实例
不需要后续转换,创建时自动返回对应代理类实例,实现方式为自定义基类管理器的create方法:
补充实现代码(基于方案a的代码新增)
class AnimalManager(models.Manager): def create(self, **kwargs): species = kwargs.get("species") proxy_class = Animal.SPECIES_PROXY_MAPPING.get(species) if isinstance(proxy_class, str): proxy_class = globals()[proxy_class] if proxy_class: # 直接用代理类创建实例,自动满足字段过滤规则 return proxy_class.objects.create(**kwargs) return super().create(**kwargs) # 给Animal基类替换自定义管理器 class Animal(models.Model): # ... 原有代码不变 objects = AnimalManager()
使用示例
# 直接创建得到对应代理类实例 cat = Animal.objects.create(species="cat") # 类型直接为Cat dog = Animal.objects.create(species="dog") # 类型直接为Dog # 查询效果和方案a完全一致
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

