我有以下概念模型:
class GenericAbstractBase(models.Model):
name = models.CharField(max_length=255)
staff = generic.GenericRelation(
"Staff",
content_type_field="content_type",
object_id_field="object_id",
)
class Meta:
abstract = True
class GenericModelA(GenericAbstractBase):
extra_a = models.CharField(max_length=255)
class GenericModelB(GenericAbstractBase):
extra_b = models.CharField(max_lenth=10)
class Staff(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
active = models.CharField(max_length=10, choices = ACTIVE_CHOICES)
limit = models.Q(app_label='staff', model='genericmodela') | models.Q(app_label='staff', model='genericmodelb')
content_type = models.ForeignKey(ContentType, limit_choices_to=limit)
object_id = models.PositiveIntegerField()
generic_object = generic.GenericForeignKey("content_type", "object_id")
在Django v1.4& Django v1.5以下查询工作正常:
>>> ctype = ContentType.objects.get_for_model(GenericModelA)
>>> Staff.objects.filter(
content_type=ctype,
genericmodela__name__icontains="a"
)
>>> [<Staff: Abbott, Kaylee>, <Staff: Adams, Kay>, ... ]
它生成的SQL(sqlite)看起来像:
SELECT
"staff_staff"."id", "staff_staff"."first_name","staff_staff"."last_name",
"staff_staff"."active","staff_staff"."content_type_id" ,"staff_staff"."object_id"
FROM "staff_staff"
INNER JOIN "staff_staff" T2 ON ("staff_staff"."id" = T2."id")
INNER JOIN "staff_genericmodela" ON (T2."object_id" = "staff_genericmodela"."id")
WHERE (
"staff_genericmodela"."name" LIKE % a % ESCAPE \ '\\\'
AND "staff_staff"."content_type_id" = 11
)
但是在Django 1.6中,查询失败并出现FieldError:
FieldError: Cannot resolve keyword 'genericmodela' into field. Choices are: active, content_type, department, first_name, id, last_name, object_id, position
以下陈述in the release notes可能相关:
Django 1.6包含对ORM的许多更改。这些变化大多分为三类:
- 错误修复(例如,通用关系的正确连接子句,查询组合,联接提升和连接修剪修复)
醇>
我的问题是,Django 1.6中发生了什么变化导致这种情况破裂?我是否坚持使用extra
或在Python中进行此类过滤?
答案 0 :(得分:1)
我找到了一些interesting information here。
作为一种解决方法,您可以执行以下操作:
ctype = ContentType.objects.get_for_model(GenericModelA)
pk_list = Staff.objects.filter(
content_type=ctype
).values_list('object_id', flat=True)
GenericModelA.objects.filter(pk__in=pk_list, name__icontains="a")
答案 1 :(得分:1)
由于未记录的行为,这似乎仅适用于Django 1.4,因此我决定在CASE
查询中使用extra
语句来执行我想要的查询。例如:
cta = ContentType.objects.get_for_model(models.GenericModelA)
ctb = ContentType.objects.get_for_model(models.GenericModelB)
extraq = """
CASE
WHEN content_type_id = {0}
THEN (SELECT extra_a from staff_genericmodela WHERE object_id = staff_genericmodela.id)
WHEN content_type_id = {1}
THEN (SELECT extra_b from staff_genericmodelb WHERE object_id = staff_genericmodelb.id)
END
""".format(cta.pk, ctb.pk)
Staff.objects.extra(select={'genericname': extraq}).extra(where=["genericname LIKE %s", params=["%{0}%".format("foobar")])
到目前为止,这对我来说效果很好,应该可以轻松扩展到其他类似案例。