【问题标题】:django serializer queries db for forign key iddjango 序列化程序查询 db 以获取外键 ID
【发布时间】:2012-02-20 14:03:30
【问题描述】:

我使用 django 序列化程序序列化了几个对象,但问题是每个序列化都从 db 查询 foerign 键的 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)

【问题讨论】:

    标签: python django serialization django-serializer


    【解决方案1】:

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

    例如:

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

    【讨论】:

      【解决方案2】:

      我最终修改了 django python 序列化程序,以便它直接获取引用对象的 id 而不是从 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)
      

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

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

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

      我还为此提交了bug,现在已在 django 主干中修复。 see changset

      【讨论】:

        【解决方案3】:

        您应该使用Natural Keys 进行序列化。

        本质上,这需要您在外键引用模型上定义一个名为 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'),)
        

        然后在序列化过程中将参数use_natural_keys设置为True

        再次,来自文档:

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

        【讨论】:

        • 这不会避免数据库查询,我想要id i.e pk 而不是自然键
        猜你喜欢
        • 2021-02-13
        • 1970-01-01
        • 1970-01-01
        • 2021-03-19
        • 1970-01-01
        • 2020-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多