- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一定是真的误解了 Django 内容类型框架中的 GenericRelation
field。
要创建一个最小的独立示例,我将使用教程中的投票示例应用程序。在 Choice
模型中添加一个通用外键字段,并创建一个新的 Thing
模型:
class Choice(models.Model):
...
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
thing = GenericForeignKey('content_type', 'object_id')
class Thing(models.Model):
choices = GenericRelation(Choice, related_query_name='things')
使用干净的数据库、同步表并创建一些实例:
>>> poll = Poll.objects.create(question='the question', pk=123)
>>> thing = Thing.objects.create(pk=456)
>>> choice = Choice.objects.create(choice_text='the choice', pk=789, poll=poll, thing=thing)
>>> choice.thing.pk
456
>>> thing.choices.get().pk
789
到目前为止一切顺利 - 这种关系在一个实例的两个方向上都有效。但是从查询集中来看,反向关系很奇怪:
>>> Choice.objects.values_list('things', flat=1)
[456]
>>> Thing.objects.values_list('choices', flat=1)
[456]
为什么反向关系再次给我 thing
的 id?我期望的是选择的主键,相当于以下结果:
>>> Thing.objects.values_list('choices__pk', flat=1)
[789]
那些 ORM 查询生成的 SQL 是这样的:
>>> print Thing.objects.values_list('choices__pk', flat=1).query
SELECT "polls_choice"."id" FROM "polls_thing" LEFT OUTER JOIN "polls_choice" ON ( "polls_thing"."id" = "polls_choice"."object_id" AND ("polls_choice"."content_type_id" = 10))
>>> print Thing.objects.values_list('choices', flat=1).query
SELECT "polls_choice"."object_id" FROM "polls_thing" LEFT OUTER JOIN "polls_choice" ON ( "polls_thing"."id" = "polls_choice"."object_id" AND ("polls_choice"."content_type_id" = 10))
Django 文档通常非常出色,但我不明白为什么第二个查询或找不到任何关于该行为的文档 - 它似乎完全从错误的表返回数据?
最佳答案
TL;DR 这是 Django 1.7 中的错误,已在 Django 1.8 中修复。
更改直接进入 master 并且没有进入弃用期,这并不奇怪,因为在这里保持向后兼容性真的很困难。更令人惊讶的是,在 1.8 release notes 中没有提到这个问题,因为修复改变了当前工作代码的行为。
此答案的其余部分描述了我如何使用 git bisect run
找到提交。它在这里仅供我自己引用,所以如果我需要再次平分一个大项目,我可以回到这里。
首先,我们设置了一个 Django 克隆和一个测试项目来重现该问题。我在这里使用 virtualenvwrapper,但您可以根据需要进行隔离。
cd /tmp
git clone https://github.com/django/django.git
cd django
git checkout tags/1.7
mkvirtualenv djbisect
export PYTHONPATH=/tmp/django # get django clone into sys.path
python ./django/bin/django-admin.py startproject djbisect
export PYTHONPATH=$PYTHONPATH:/tmp/django/djbisect # test project into sys.path
export DJANGO_SETTINGS_MODULE=djbisect.mysettings
创建以下文件:
# /tmp/django/djbisect/djbisect/models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class GFKmodel(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
gfk = GenericForeignKey()
class GRmodel(models.Model):
related_gfk = GenericRelation(GFKmodel)
还有这个:
# /tmp/django/djbisect/djbisect/mysettings.py
from djbisect.settings import *
INSTALLED_APPS += ('djbisect',)
现在我们有了一个工作项目,创建 test_script.py
以与 git bisect run
一起使用:
#!/usr/bin/env python
import subprocess, os, sys
db_fname = '/tmp/django/djbisect/db.sqlite3'
if os.path.exists(db_fname):
os.unlink(db_fname)
cmd = 'python /tmp/django/djbisect/manage.py migrate --noinput'
subprocess.check_call(cmd.split())
import django
django.setup()
from django.contrib.contenttypes.models import ContentType
from djbisect.models import GFKmodel, GRmodel
ct = ContentType.objects.get_for_model(GRmodel)
y = GRmodel.objects.create(pk=456)
x = GFKmodel.objects.create(pk=789, content_type=ct, object_id=y.pk)
query1 = GRmodel.objects.values_list('related_gfk', flat=1)
query2 = GRmodel.objects.values_list('related_gfk__pk', flat=1)
print(query1)
print(query2)
print(query1.query)
print(query2.query)
if query1[0] == 789 == query2[0]:
print('FIXED')
sys.exit(1)
else:
print('UNFIXED')
sys.exit(0)
脚本必须是可执行的,所以用 chmod +x test_script.py
添加标志。它应该位于 Django 被克隆到的目录中,即 /tmp/django/test_script.py
对我来说。这是因为 import django
应该首先选择本地 checkout 的 django 项目,而不是站点包中的任何版本。
git bisect 的用户界面旨在找出错误出现的位置,因此当您试图找出某个错误时,通常的“坏”和“好”前缀是倒过来的错误已修复。这可能看起来有些颠倒,但如果错误存在,测试脚本应该成功退出(返回代码 0),如果错误被修复,它应该失败(返回代码非零)。这让我绊倒了几次!
git bisect start --term-new=fixed --term-old=unfixed
git bisect fixed tags/1.8
git bisect unfixed tags/1.7
git bisect run ./test_script.py
所以这个过程将进行自动搜索,最终找到修复错误的提交。这需要一些时间,因为在 Django 1.7 和 Django 1.8 之间有很多提交。它将 1362 个修订一分为二,大约 10 个步骤,最终输出:
1c5cbf5e5d5b350f4df4aca6431d46c767d3785a is the first fixed commit
commit 1c5cbf5e5d5b350f4df4aca6431d46c767d3785a
Author: Anssi Kääriäinen <akaariai@gmail.com>
Date: Wed Dec 17 09:47:58 2014 +0200
Fixed #24002 -- GenericRelation filtering targets related model's pk
Previously Publisher.objects.filter(book=val) would target
book.object_id if book is a GenericRelation. This is inconsistent to
filtering over reverse foreign key relations, where the target is the
related model's primary key.
这正是查询从不正确的 SQL(从错误的表中获取数据)发生更改的提交
SELECT "djbisect_gfkmodel"."object_id" FROM "djbisect_grmodel" LEFT OUTER JOIN "djbisect_gfkmodel" ON ( "djbisect_grmodel"."id" = "djbisect_gfkmodel"."object_id" AND ("djbisect_gfkmodel"."content_type_id" = 8) )
进入正确的版本:
SELECT "djbisect_gfkmodel"."id" FROM "djbisect_grmodel" LEFT OUTER JOIN "djbisect_gfkmodel" ON ( "djbisect_grmodel"."id" = "djbisect_gfkmodel"."object_id" AND ("djbisect_gfkmodel"."content_type_id" = 8) )
当然,我们可以从提交哈希中轻松地在 github 上找到拉取请求和票证。希望有一天这也能帮助其他人 - 由于迁移,平分 Django 可能很难设置!
关于python - 如何使用 GenericRelation 的逆函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36163430/
我有一个事件对象,除了 Notes 之外,还有其他对象与 Event 有一般关系,并且没有事件字段。现在我希望能够编写一个查询来排除所有 Events,其中 Notes 的事件字段为 False。所以
在 Django 项目中,我有这样定义的模型: from django.db import models from django.contrib.contenttypes.models import
我想找到与我的角色相关且适合各种类别的属性。最终我想要这个输出: "Attributes": { "Physical": { "Level": 1,
我一定是真的误解了 Django 内容类型框架中的 GenericRelation field。 要创建一个最小的独立示例,我将使用教程中的投票示例应用程序。在 Choice 模型中添加一个通用外键字
我有 mixin 和模型: class Mixin(object): field = GenericRelation('ModelWithGR') class MyModel(Mixin, m
假设我有几个代表现实生活对象的模型:“人”、“椅子”、“房间” 我还有一个“Collection”模型,它代表了这些模型的一些记录集合。 每个模型可以是多个集合的成员——因此,我还创建了一个“Memb
我在将 GenericRelation 与 update_or_create 结合使用时遇到问题。我有以下型号: class LockCode(TimeStampedModel): conte
我想进行数据迁移,以便在数据库中添加用户阅读帖子。有这样的代码: def user_read_posts(apps, schema_editor): User = apps.get_model
我正在建立词汇表并有以下模型: class Word(Model): name = CharField(max_length=75) class EnNoun(Model): word = One
我有一个像这样的文章模型 from django.contrib.contenttypes.fields import GenericRelation from django.db import mo
我的 Django 应用程序中有这两个模型: class ItemOrigin(models.Model): content_type = models.ForeignKey(ContentT
我有以下错误: django.core.exceptions.FieldError: 'pictures' cannot be specified for Building model form as
我正在使用django-import-export导出记录的模块。但是,我无法导出通用关系。我只想获取 GenericRelation 的所有详细信息。 在 Github 中找到了下面的代码片段,但它
在我的 Django 项目中,我有一个名为 Value 的模型,它具有这样的 GenericForeignKey: class Value(models.Model): content_typ
更新:关于此问题的公开标记:24272 到底是怎么回事? Django 有一个 GenericRelation类,它添加了一个“反向”通用关系以启用额外的API。 事实证明,我们可以将这个 rever
我有一些 Django 模型通用关系字段,我希望它们出现在 graphql 查询中。 Graphite 烯是否支持通用类型? class Attachment(models.Model): u
我想包含一个带有 GenericRelation 的模型DRF 中的反向引用 文档表明这应该很容易(就在上面:http://www.django-rest-framework.org/api-guid
我是一名优秀的程序员,十分优秀!