Django: select_related и GenericRelation

Работает ли select_related для отношений GenericRelation или есть разумная альтернатива? В данный момент Django выполняет отдельные вызовы sql для каждого элемента в моем наборе запросов, и я бы хотел избежать этого, используя что-то вроде select_related.

class Claim(models.Model):
    proof = generic.GenericRelation(Proof)


class Proof(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

Я выбираю группу претензий, и я хотел бы, чтобы соответствующие доказательства были выдвинуты вместо индивидуальных запросов.

3 ответа

Решение

Похоже, что select_related и GR не работают вместе. Я полагаю, вы могли бы написать какой-нибудь аксессор для Claim, который получит их через один и тот же запрос Этот пост дает вам несколько указателей на сырой SQL, чтобы получить универсальные объекты, если они вам нужны

Нет встроенного способа сделать это. Но я выложил технику для симуляции select_related об общих отношениях в моем блоге.


Содержание блога обобщено:

Мы можем использовать Джанго _content_object_cache поле, чтобы по существу создать наш собственный select_related для родовых отношений.

generics = {}
for item in queryset:
    generics.setdefault(item.content_type_id, set()).add(item.object_id)

content_types = ContentType.objects.in_bulk(generics.keys())

relations = {}
for ct, fk_list in generics.items():
    ct_model = content_types[ct].model_class()
    relations[ct] = ct_model.objects.in_bulk(list(fk_list))

for item in queryset:
    setattr(item, '_content_object_cache', 
            relations[item.content_type_id][item.object_id])

Здесь мы получаем все различные типы контента, используемые отношениями в наборе запросов, и набор отдельных идентификаторов объектов для каждого из них, а затем используем встроенный метод менеджера in_bulk, чтобы получить все типы контента одновременно в удобном и готовом к работе -используемый словарь по идентификатору. Затем мы делаем один запрос для каждого типа контента, снова используя in_bulk, чтобы получить весь фактический объект.

Наконец, мы просто устанавливаем соответствующий объект в поле _content_object_cache исходного элемента. Причина, по которой мы это делаем, заключается в том, что это атрибут, который Django будет проверять и заполнять при необходимости, если вы вызвали x.content_object напрямую. Предварительно заполнив его, мы гарантируем, что Django никогда не нужно будет вызывать индивидуальный поиск - по сути, мы реализуем своего рода select_related() для родовых отношений.

Вы можете использовать функцию.extra() для ручного извлечения полей:

Claims.filter(proof__filteryouwant=valueyouwant).extra(select={'field_to_pull':'proof_proof.field_to_pull'})

.Filter() выполнит соединение,.extra() потянет поле. proof_proof - имя таблицы SQL для модели Proof. Если вам нужно более одного поля, укажите каждое из них в словаре.

Другие вопросы по тегам