Сериализатор django запрашивает в БД идентификатор внешнего ключа - PullRequest
2 голосов
/ 27 января 2012

Я сериализую несколько объектов, используя сериализатор django, но проблема заключается в том, что каждый из них сериализует запрос идентификатора ключа foerign из db, а не просто берет его из объекта, например,

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)

Ответы [ 3 ]

1 голос
/ 27 января 2012

Я закончил тем, что модифицировал сериализатор Python django, чтобы он напрямую получал идентификатор объекта, на который ссылаются, вместо того, чтобы получать его из 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' }

Я также подал ошибку для этого, которая теперь исправлена ​​в стволе django. см. Changset

0 голосов
/ 09 июня 2013

То, что я делаю, чтобы избежать лишних запросов, тоже кажется не очень эффективным, но это помогает: добавьте select_related(...) к исходному набору запросов, чтобы загрузить связанные объекты в начальном запросе.

Например:

a = QBAccount.allobjects.select_related('company').all()[0]
0 голосов
/ 27 января 2012

Вы должны сериализовать, используя 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...