Задать вопрос

Как упростить запрос, может переписать одним SQL запросом?

Есть несколько таблиц. Проект уже написан, все работает замечательно, но вот нужно вывести таблицу с данными различными, и из различных таблиц. Предпринимал попытки все это написать одним ORM запросом, потом SQL, в итоге решил собрать все данные во views и выдать на рендеринг в шаблон.

Вот таблицы:
class Contest(models.Model):
    title = models.CharField(max_length=255)
    slug = models.CharField(max_length=50)
    date_start = models.DateTimeField(_("Date Start"), null=True, blank=True)
    date_end = models.DateTimeField(_("Date End"), null=True, blank=True)

class Element(models.Model):
    contest = models.ForeignKey(Contest, blank=True, null=True)
    title = models.CharField(max_length=255)
    weight = models.IntegerField(_('Weight'), blank=True, default=1)

class UserActiv(models.Model):
    user = models.ForeignKey(User)
    contest = models.ForeignKey(Contest)
    date_activation = models.DateTimeField(_("Activation Date"), auto_now_add=True)

class Data(models.Model):
    useractive = models.ForeignKey(UserActiv)
    element = models.ForeignKey(Element, blank=True, null=True)
    date_review = models.DateTimeField(_("Date Review"), auto_now_add=True)
    showing = models.IntegerField(_('Showing'), blank=True, default=0)


Вот так, как мне кажется не правильно, собираю данные:
...
active_contest = get_object_or_404(Contest, slug = slug)

table_users = []
header_table = []

for element in Element.objects.filter(contest = active_contest):
  	header_table.append(element.title)

for user in UserActiv.objects.filter(contest = active_contest):
  	tmp_user = {}

  	tmp_user.update({
    		'username': get_object_or_none(User, id = user.user.id).username
  	})
  	element_value = []
  	for el in Element.objects.filter(contest = active_contest):
    		element_value.append(Data.objects.filter(showing=2, useractive=user.id, element = el.id).count())
  	tmp_user.update({
    		'el': element_value
  	})
  	tmp_user.update(
    		Element.objects.filter(data__showing=2, data__useractive=user.id).aggregate(sum_weight=Sum('weight'))
  	)
  	try:
    		tmp_user.update({
      			'last_date_find_element': Data.objects.filter(showing=2, useractive=user.id).order_by('-date_review')[:1].get().date_review
    		})
  	except:
    		tmp_user.update({
      			'last_date_find_element': None
    		})

  	table_users.append(tmp_user)

render_dict.update({
  	'table_users': table_users,
  	'header_table': header_table
})
return render_to_response('contest_users.html', render_dict,
context_instance=RequestContext(request))


В итоге я получаю
  • список полей в заголовок (так как там может быть различное количество из таблицы Element)
  • ник юзера из главной таблицы User
  • количество вхождений каждого элемента из Element
  • общую сумму всех вхождений по весу из Element
  • дату последней записи в Data


Подозреваю что хоть реализация и грязная, производительность стремится вниз, но как по другому собрать все данные не приходит в голову.
Может будут у кого идеи.
  • Вопрос задан
  • 207 просмотров
Подписаться 1 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 1
crazyzubr
@crazyzubr
Python backend-developer
Вместо этого

for element in Element.objects.filter(contest = active_contest):
  	header_table.append(element.title)


Надо так:

header_table = Element.objects.filter(contest = active_contest).values_list('title', flat=True)


Совсем непонятный способ тут:

tmp_user.update({
    		'username': get_object_or_none(User, id = user.user.id).username
  	})


Когда можно так

tmp_user['username'] = user.user.username if user.user else None


Вместо этого

try:
    		tmp_user.update({
      			'last_date_find_element': Data.objects.filter(showing=2, useractive=user.id).order_by('-date_review')[:1].get().date_review
    		})
  	except:
    		tmp_user.update({
      			'last_date_find_element': None
    		})


Можно проще:

data_obj = Data.objects.filter(showing=2, useractive=user.id).order_by('-date_review').first()
tmp_user['last_date_find_element'] = data_obj.date_review if data_obj else None


В целом можно это все переписать на меньшее количество запросов, но неудобно писать в этот текстовое поле здесь. Да и до всего постепенно должны дойти сами, иначе это медвежья услуга может получиться))
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
Strikt Москва
от 100 000 до 180 000 ₽
ITK academy Саратов
от 75 000 ₽
Sim-Ba Pay Санкт-Петербург
от 180 000 ₽