所以我在Django App中有以下模型结构: -
class SuperModel(models.Model):
f1 = models.CharField()
f2 = models.CharField()
class Model(SuperModel):
f3 = models.CharField()
class OverrideModel(models.Model):
fpk = models.OneToOneField(Model, primary_key=True)
f1 = models.CharField()
f2 = models.CharField()
基本上,在我的应用程序中,f1
表中的字段f2
和Model
包含我输入的用户信息。用户可以覆盖此信息,并且他/她在数据中所做的任何更改都存储在OverrideModel
表中(因为我不想丢失我先输入的信息)。可以把它想象成我之前创建用户配置文件,而现在我希望用户能够编辑他/她自己的配置文件而不会丢失我输入的有关它们的信息。
现在,由于我的应用程序的其余部分(views / templates etal)使用Model类中的字段名称,我想要的是创建一个视图获取字段的数据{ {1}}来自覆盖表(如果存在),否则它应该从之前的表中提取f1
,而不使用来使用原始查询集。
我将描述到目前为止我所考虑的所有内容,以便我正在处理的其他一些限制变得清晰: -
f1
。
这会抛出注释别名与表中已有字段冲突的错误。
Model.objects.annotate(f1=Case(When(overridemodel__f1__isnull=True, then=F('f1')), default=F('overridemodel__f1')))
。
这种方法无法应用,因为我无法找到使用extra来应用外连接的方法。覆盖模型可能没有与每个模型行对应的行。在Model.objects.defer('f1').extra(select={'f1': 'CASE WHEN ... END'}, tables=..., where=...)
子句中指定覆盖表执行跨产品操作,该操作结合可用于执行内连接的位置,而不是外连接(尽管我很高兴被证明是错误的)。 / p>
编辑:我已经意识到select_related可能能解决上述问题,但如果我在字段tables
上过滤Model.objects.select_related('overridemodel').defer('f1').extra(select={'f1': 'CASE WHEN ... END'}, tables=..., where=...)
生成的查询集,请说{{ 1}}过滤查询的where子句使用f1
字段而不是额外生成的qs.filter(f1='Random stuff')
字段。所以这种做法也是徒劳的。
使用Model.f1
获取原始查询集。
这是一个非首发,因为Django ORM在使用f1
后变得无用,我需要能够将模型对象作为应用程序的一部分进行过滤/排序。
在Model.objects.raw()
类上定义方法/属性。
同样,我将无法使用相同的字段名称,这些字段名称涉及搜索所有用法和进行更改的代码。
在数据库中创建一个视图,它可以提供我想要的内容,并创建一个从该视图中读取数据的非托管模型。
这可能是我的问题的最佳解决方案,但之前从未使用过非托管模型,我不确定如何解决它或我可能遇到的陷阱。我能想到的一个问题是,我的视图总是必须与模型保持同步,但与搜索代码库并进行更改然后测试以查看是否相比,这似乎是一个很小的代价。任何事情都破了。
所以,你有它。与往常一样,任何帮助/指针将不胜感激。我试图提供尽可能少的例子;因此,如果需要更多信息,我很乐意提供。
另外,我正在使用Django 1.8和MySQL。
答案 0 :(得分:0)
我意识到没有简单的规范方法来解决我的问题。即使使用选项5(创建使用非托管模型进行ORM操作的视图),我也会丢失原始模型上用于过滤/排序的相关查询名称。
所以,对于有类似问题的其他人,我会推荐我最终使用的方法,它不会保留OverrideModel,而是一个OverriddenModel,它保存每当用户进行更改时覆盖的值并使用覆盖更新原始模型值,以便模型始终包含将要进行过滤/查询的值