You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django如何自动延迟主模型及关联模型的TextField与本地化字段

在Django中自动延迟主模型及关联模型的大文本字段

要实现自动排除主模型和关联模型中description、description_xx、text、text_xx这类大文本字段(仅在需要时加载),可以通过自定义QuerySet和Manager统一处理,无需每次查询手动调用defer()。

1. 编写通用字段匹配函数

先实现一个函数,自动识别模型中符合命名规则的TextField:

import re
from django.db import models

def get_deferred_fields(model):
    deferred_fields = []
    # 匹配规则:匹配description/text开头,可选跟双字符语言后缀(如_uk、_ru)
    field_pattern = re.compile(r'^(description|text)(_\w{2})?$')
    
    for field in model._meta.get_fields():
        # 只筛选TextField且字段名符合规则的字段
        if isinstance(field, models.TextField) and field_pattern.match(field.name):
            deferred_fields.append(field.name)
    
    return deferred_fields

2. 自定义QuerySet实现自动延迟

创建自定义QuerySet,重写查询逻辑,自动对主模型和关联模型应用字段延迟:

class DeferredTextQuerySet(models.QuerySet):
    def defer_text_fields(self):
        # 延迟主模型的目标字段
        queryset = self.defer(*get_deferred_fields(self.model))
        
        # 自动处理一级关联模型(外键/一对一关联)
        for rel in self.model._meta.related_objects:
            rel_model = rel.related_model
            rel_deferred = get_deferred_fields(rel_model)
            # 转换为跨模型字段格式,如product__description
            queryset = queryset.defer(*[f"{rel.name}__{field}" for field in rel_deferred])
            
            # 处理二级关联模型(如Product关联的Manufacturer)
            for sub_rel in rel_model._meta.related_objects:
                sub_rel_model = sub_rel.related_model
                sub_deferred = get_deferred_fields(sub_rel_model)
                queryset = queryset.defer(*[f"{rel.name}__{sub_rel.name}__{field}" for field in sub_deferred])
        
        return queryset
    
    # 让默认的all()方法自动应用延迟规则
    def all(self):
        return self.defer_text_fields()

3. 给模型绑定自定义Manager

将自定义QuerySet绑定到模型的Manager上,让模型的默认查询自动生效:

class DeferredTextManager(models.Manager):
    def get_queryset(self):
        return DeferredTextQuerySet(self.model, using=self._db)

# 给你的模型绑定Manager
class StoreItem(models.Model):
    store_id = models.IntegerField()
    product = models.ForeignKey('Product', on_delete=models.CASCADE)
    price_in = models.DecimalField(max_digits=10, decimal_places=2)
    price_out = models.DecimalField(max_digits=10, decimal_places=2)
    count = models.IntegerField()
    
    objects = DeferredTextManager()

# 同样给Product和ProductManufacturer绑定Manager
class Product(models.Model):
    name = models.CharField(max_length=255)
    name_uk = models.CharField(max_length=255)
    description = models.TextField()
    description_uk = models.TextField()
    manufacturer = models.ForeignKey('ProductManufacturer', on_delete=models.SET_NULL, null=True)
    
    objects = DeferredTextManager()

class ProductManufacturer(models.Model):
    name = models.CharField(max_length=255)
    description = models.TextField()
    text = models.TextField()
    
    objects = DeferredTextManager()

4. 处理预取关联(prefetch_related)

如果使用prefetch_related查询多对多或反向关联,需要给预取的QuerySet也应用延迟规则:

# 示例:预取Product和Manufacturer时自动延迟大文本字段
StoreItem.objects.prefetch_related(
    models.Prefetch('product', queryset=Product.objects.defer_text_fields()),
    models.Prefetch('product__manufacturer', queryset=ProductManufacturer.objects.defer_text_fields())
).all()

效果验证

执行如下查询:

StoreItem.objects.select_related('product', 'product__manufacturer').all()

生成的SQL会自动排除所有符合规则的大文本字段,与你期望的查询结构一致。

内容的提问来源于stack exchange,提问作者Igor Kremin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 01:17:48