如何从子模型视图及后台访问基模型定义的翻译字段?
问题描述
接手一个Django项目,包含基于PolymorphicModel的多态模型,原结构如下:
from django.db import models from polymorphic.models import PolymorphicManager, PolymorphicModel class Product(PolymorphicModel): name=models.CharField(max_length=127) objects=PolymorphicManager() class Book(Product): pass class Drink(Product): pass
无法修改多态方案,需要用Parler给基模型Product的name字段添加翻译功能。修改后的模型代码存在笔误,调整前的版本如下:
from django.db import models from parler.models import TranslatableModel, TranslatedFields from parler.managers import TranslatableManager, TranslatableQuerySet from polymorphic.models import PolymorphicManager, PolymorphicModel from polymorphic.query import PolymorphicQuerySet class ProductQuerySet(PolymorphicQuerySet, TranslatableQuerySet): pass class ProductManager(PolymorphicManager, TranslatableManager): queryset_class = MarkerQuerySet # 笔误:应为ProductQuerySet class Product(PolymorphicModel): translations = TranslatedFields( name=models.CharField(max_length=127) # 缺失闭合括号 objects=ProductManager() class Book(Product): pass class Drink(Product): pass
在Django Shell中测试正常,但出现两个问题:
- 接口测试报错:
.venv/lib/python3.12/site-packages/django/db/models/sql/query.py:1577: in _add_q child_clause, needed_inner = self.build_filter ... > arg, value = filter_expr E ValueError: too many values to unpack (expected 2)
- 访问子模型后台管理页面报错:
Cannot resolve keyword 'name' into field.
解决方案
1. 修正模型核心问题
首先修复笔误,同时让Product继承TranslatableModel——这是Parler翻译功能生效的必要条件,也是后台找不到字段的核心原因。调整后的模型代码:
from django.db import models from parler.models import TranslatableModel, TranslatedFields from parler.managers import TranslatableManager, TranslatableQuerySet from polymorphic.models import PolymorphicManager, PolymorphicModel from polymorphic.query import PolymorphicQuerySet class ProductQuerySet(PolymorphicQuerySet, TranslatableQuerySet): pass class ProductManager(PolymorphicManager, TranslatableManager): queryset_class = ProductQuerySet # 修正笔误 class Product(TranslatableModel, PolymorphicModel): # 同时继承两个基类 translations = TranslatedFields( name=models.CharField(max_length=127) ) # 补全闭合括号 objects = ProductManager() class Book(Product): pass class Drink(Product): pass
2. 修复查询集兼容性问题
Polymorphic和Parler的查询集混合时,方法调用顺序可能冲突,导致过滤报错。重载查询集的filter方法,优先让Parler处理翻译字段逻辑:
class ProductQuerySet(PolymorphicQuerySet, TranslatableQuerySet): def filter(self, *args, **kwargs): # 先处理翻译字段过滤,再交给多态逻辑处理 return super(TranslatableQuerySet, self).filter(*args, **kwargs)
3. 适配Django后台管理
子模型的Admin类必须继承ParlerAdmin,才能正确识别翻译字段:
from django.contrib import admin from parler.admin import TranslatableAdmin from .models import Book, Drink class BookAdmin(TranslatableAdmin): list_display = ('name',) # 直接使用翻译字段,Parler自动处理多语言 class DrinkAdmin(TranslatableAdmin): list_display = ('name',) admin.site.register(Book, BookAdmin) admin.site.register(Drink, DrinkAdmin)
4. 数据迁移注意事项
执行迁移前,需要把原Product表的name字段数据迁移到Parler的翻译表中,示例迁移脚本:
from django.db import migrations def migrate_name_to_translations(apps, schema_editor): Product = apps.get_model('product', 'Product') ProductTranslation = apps.get_model('product', 'ProductTranslation') # 把原有name值导入默认语言的翻译记录 for product in Product.objects.all(): ProductTranslation.objects.get_or_create( master=product, language_code='en', # 替换为项目默认语言 defaults={'name': product.name} ) class Migration(migrations.Migration): dependencies = [ ('product', '0002_auto_xxxxxx_xxxx'), # 对应添加TranslatedFields后的迁移文件 ] operations = [ migrations.RunPython(migrate_name_to_translations), migrations.RemoveField( model_name='product', name='name', ), ]
内容的提问来源于stack exchange,提问作者kaan_atakan
相关产品推荐
相关产品推荐

