#python #django #orm
#python #django #orm
Вопрос:
Я пытаюсь выполнить запрос от родителя к дочернему и с помощью одного запроса могу получить дочерние результаты в parent. В моем примере я пытаюсь установить связь между таблицами i18n, в которые я хочу включить строку из дочерней таблицы одним нажатием.
models.py
class main(models.Model):
slug = models.SlugField()
is_active = models.BooleanField(default=True)
site = models.ForeignKey(Site)
def __unicode__(self):
return self.slug
class main_i18n(models.Model):
main = models.ForeignKey(main)
language = models.CharField(max_length=2, choices=LANGUAGES)
title = models.CharField(max_length=50)
class Meta:
unique_together = (("language", "main"))
def __unicode__(self):
return self.title
Я попытался выполнить следующий запрос
a=main.objects.filter(is_active=True, main_i18n__language='en')
и соотношение выполнено идеально, вот что я увидел, когда попытался напечатать запрос
>>> a.query.__str__()
'SELECT `category_main`.`id`, `category_main`.`slug`, `category_main`.`is_active`, `category_main`.`site_id` FROM `category_main` INNER JOIN `category_main_i18n` ON (`category_main`.`id` = `category_main_i18n`.`main_id`) WHERE (`category_main_i18n`.`language` = en AND `category_main`.`is_active` = True )'
Как вы видите из запроса, он выполняет объединение правильно, но имена столбцов не включены в инструкцию select . Я не могу получить доступ к данным main_i18n при попытке выполнить цикл for.
извините за мой паршивый английский и надеюсь, что смогу найти помощь,
Наилучшие пожелания,
—- РЕДАКТИРОВАТЬ:
ниже приведен шаблон, который я использую в настоящее время, в конечном счете, я действительно хотел бы создать единый запрос и выполнить перегруппировку на основе списка данных в моем представлении.
<table class="homepage-listing">
<tr>
<td>
{# {% regroup list by main as rg_main %}#}
{% for obj in main %}
{# {% if obj.grouper != None %}#}
<div class="listing-block">
<a href="#" ><h3>{{ obj }}</h3></a>
<ul>
{% for s in obj.list %}
<li>{{ s.list_i18n_set.get }} </li>
{% endfor %}
</ul>
</div>
{# {% endif %}#}
{% endfor %}
</td>
</tr>
</table>
— РЕДАКТИРОВАТЬ:
Мне пришлось использовать дополнительные функции, чтобы создать один запрос для этой цели. Я начал с этого, но немного усложняюсь, пытаюсь убедиться, что столбцы, не жестко закодированные в запросах, и соединения верны. Кто-нибудь может сказать мне, есть ли лучший способ написать запрос?
dict = Main.objects.extra(
select=
{
'main_title' : '%s.%s' % (MainI18n._meta.db_table, MainI18n._meta.get_field('title').verbose_name),
'list_title' : '%s.%s' % (ListI18n._meta.db_table, ListI18n._meta.get_field('title').verbose_name),
},
tables=[
'%s' % (MainI18n._meta.db_table),
'%s' % (List._meta.db_table),
'%s' % (ListI18n._meta.db_table),
],
where=[
'%s.%s=%s.%s' % (MainI18n._meta.db_table, 'main_id', Main._meta.db_table, 'id'),
'%s.main_id=%s.id' % (List._meta.db_table, Main._meta.db_table),
'%s.list_id=%s.id' % (ListI18n._meta.db_table, List._meta.db_table),
'category_listi18n.language="%s"' % (request.LANGUAGE_CODE)
]).select_related().filter(maini18n__language=request.LANGUAGE_CODE )
Комментарии:
1. Не могли бы вы показать цикл, который вы используете? Насколько я понимаю, select_related сохраняет дополнительный запрос к БД при вызове атрибута в вашей связанной модели, но данные, тем не менее, должны быть доступны для извлечения даже без select_related.
2. select_related работает только «вперед». Поскольку поиск выполняется не в той модели, в которой определен fk, select_related не будет извлекать данные из базы данных.
3. Я только что обновил сообщение, добавив также код шаблона.
Ответ №1:
Когда вы используете внешний ключ, вам необходимо получить доступ к этим данным через RelatedManager. В вашем случае вы получили бы доступ к данным в main_i18n из основного, например:
>>> a=main.objects.get(id=1)
>>> i18n = a.main_i18n_set.get()
>>> i18n.language
u'en'
или если вам нужно работать с несколькими объектами:
a = main.objects.filter(is_active=True, main_i18n__language='en')
for obj in a:
i18n = obj.main_i18n_set.get()
print i18n.language
который, конечно, печатал бы ‘en’ для каждого объекта, возвращаемого фильтром.
Комментарии:
1. Кроме того, вы можете использовать.main_i18n_set.all(), чтобы получить все экземпляры связанной модели.
2. Хороший момент. RelatedManager действует так же, как и другие менеджеры, поэтому вы можете запускать filter, all, get и т.д. В main_i18n_set .
3. @крис, спасибо за ответ, то, что ты упомянул, работает. Но если я передам «a» в шаблон, мне придется обращаться к базе данных для таблицы i18n столько, сколько записей в «a». Есть идеи, как я могу избежать этой ситуации?
4. Это когда вы используете select_related .
5. Я должен рассказать вам об этом: a=main.objects.filter(is_active= True, main_i18n__language=’en’). select_related(depth = 1) # глубина по сути, это количество внешних ключей, на которые будет направлен выбор.
Ответ №2:
Вместо этого вы могли бы запросить MainI18N
:
MainI18N.objects.filter(main__is_active=True, language='en').select_related('main')
РЕДАКТИРОВАТЬ: Вы можете обернуть это в пользовательский метод набора запросов. Быстрое решение (которое не позволяет вам дополнительно фильтровать набор запросов) будет выглядеть примерно так:
class MainQuerySet(QuerySet):
def translate(self, lang):
for obj in MainI18N.filter(language=lang, main__in=self).select_related('main'):
main = obj.main
main.i18n = obj
yield main
Комментарии:
1. я пытаюсь избежать этого подхода, потому что тогда моя логика приложения будет построена на основе запросов к таблицам перевода почти все время. Что-нибудь еще вы можете порекомендовать для моего случая?
2. даже если у вас есть предложения по внесению изменений в модель
3. Вы могли бы обернуть это в пользовательский метод набора запросов для
Main
(я отредактирую свой ответ). Если все остальное не удается, вы все равно можете использоватьQuerySet.extra()
.4. @emullbreh: Я перепробовал почти все подходы, и я думаю, что extra является самым мощным и гибким для создания одного сложного запроса со всеми моими результатами. Я только что обновил свой вопрос в запросе, может быть, вы можете помочь мне упростить его, если вам известен какой-либо метод .. приветствуется