django序列化器查询数据库的外键ID

发布于 2024-12-29 06:09:57 字数 1110 浏览 0 评论 0原文

我使用 django 序列化器序列化多个对象,但问题是每个序列化都会从数据库查询外键的 id,而不是仅仅从对象中获取它,例如,

class QBAccount(CompanyModel):
    company = models.ForeignKey(Company)

>>> from deretoapp.models import QBAccount
>>> import logging
>>> l = logging.getLogger('django.db.backends')
>>> l.setLevel(logging.DEBUG)
>>> l.addHandler(logging.StreamHandler())
>>> a = QBAccount.allobjects.all()[0]
>>> from django.core import serializers
>>> serializers.serialize('python', [a])
(0.000) SELECT `deretoapp_company`.`id`, ... FROM `deretoapp_company` WHERE `deretoapp_company`.`id` = 45995613-adeb-488f-9556-d69e856abe5f ; args=(u'45995613-adeb-488f-9556-d69e856abe5f',)
[{'pk': u'3de881eb-8409-4089-8de8-6e24f7281f37', 'model': u'deretoapp.qbaccount', 'fields': {... 'company': u'45995613-adeb-488f-9556-d69e856abe5f' ....}}]

有没有办法在不修改 django 代码的情况下更改此行为?我知道 a.company.id 将查询公司表(这在理想世界中不应该发生),但是序列化程序中有一个选项可以执行类似 a.company_id 的操作这不会查询数据库

>>> django.VERSION
(1, 3, 1, 'final', 0)

I serialize several objects using django serializer but problem is each serialize queries the foerign key's id from db, instead of just taking it from object e.g.

class QBAccount(CompanyModel):
    company = models.ForeignKey(Company)

>>> from deretoapp.models import QBAccount
>>> import logging
>>> l = logging.getLogger('django.db.backends')
>>> l.setLevel(logging.DEBUG)
>>> l.addHandler(logging.StreamHandler())
>>> a = QBAccount.allobjects.all()[0]
>>> from django.core import serializers
>>> serializers.serialize('python', [a])
(0.000) SELECT `deretoapp_company`.`id`, ... FROM `deretoapp_company` WHERE `deretoapp_company`.`id` = 45995613-adeb-488f-9556-d69e856abe5f ; args=(u'45995613-adeb-488f-9556-d69e856abe5f',)
[{'pk': u'3de881eb-8409-4089-8de8-6e24f7281f37', 'model': u'deretoapp.qbaccount', 'fields': {... 'company': u'45995613-adeb-488f-9556-d69e856abe5f' ....}}]

Is there a way to change this behavior without modifying django code? I know a.company.id will query company table (which should not happen in ideal world) but is there an option in serializer so that it does something like a.company_id which will not query the db

>>> django.VERSION
(1, 3, 1, 'final', 0)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

巴黎盛开的樱花 2025-01-05 06:09:57

我最终修改了 django python 序列化器,以便它直接获取引用对象的 id,而不是从数据库获取它

from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer

class Serializer(PythonSerializer):
    internal_use_only = False

    def handle_fk_field(self, obj, field): 
        if not self.use_natural_keys:
            # directly get the id
            self._current[field.name] = getattr(obj, field.attname)
            return

        return super(Serializer, self).handle_fk_field(obj, field)

我不确定它是否处理所有 ForeighKey 用例,但它适用于像 这样的简单情况company = models.ForeignKey(Company)

还需要在settings.py中注册序列化器

SERIALIZATION_MODULES = { 'python' : 'myapp.serializers.python' }

我还提交了 bug ,现已在 django trunk 中修复。
查看变更集

I ended up modifying django python serializer so that it directly gets referenced object's id instead of getting it from db

from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer

class Serializer(PythonSerializer):
    internal_use_only = False

    def handle_fk_field(self, obj, field): 
        if not self.use_natural_keys:
            # directly get the id
            self._current[field.name] = getattr(obj, field.attname)
            return

        return super(Serializer, self).handle_fk_field(obj, field)

I am not sure if it takes care of all ForeighKey usecase but it works for simple cases like company = models.ForeignKey(Company)

Also need to register serializer in settings.py

SERIALIZATION_MODULES = { 'python' : 'myapp.serializers.python' }

I also filed a bug for this, which is now fixed in django trunk.
see changset

瑶笙 2025-01-05 06:09:57

您应该使用自然键

本质上,这需要您在外键引用模型上定义一个名为 natural_key 的方法,该方法返回您希望拥有的字段,代替

文档中的 pk:

class Person(models.Model):
    objects = PersonManager()

    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    birthdate = models.DateField()

    def natural_key(self):
        return (self.first_name, self.last_name)

    class Meta:
        unique_together = (('first_name', 'last_name'),)

然后设置参数 <序列化期间将 code>use_natural_keys 设置为 True

再次,从文档中:

>>> serializers.serialize('json', [book1, book2], indent=2, use_natural_keys=True)

You should serialize using Natural Keys.

Essentially, this requires your to define a method called natural_key on the foreign key referenced model, that returns the fields you would rather have, in the place of the pk

From the documentation:

class Person(models.Model):
    objects = PersonManager()

    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    birthdate = models.DateField()

    def natural_key(self):
        return (self.first_name, self.last_name)

    class Meta:
        unique_together = (('first_name', 'last_name'),)

and then set the parameter use_natural_keys to True during serialization.

Again, from the documentation:

>>> serializers.serialize('json', [book1, book2], indent=2, use_natural_keys=True)
睫毛上残留的泪 2025-01-05 06:09:57

我为避免额外查询所做的事情似乎也不是很有效,但它确实有效:将 select_lated(...) 添加到原始查询集中,以在初始查询中加载相关对象。

例如:

a = QBAccount.allobjects.select_related('company').all()[0]

What I am doing to avoid the extra queries seems not very efficient either, but it does the trick: add select_related(...) to your original queryset to load the related objects in the initial query.

For example:

a = QBAccount.allobjects.select_related('company').all()[0]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文