Как упростить запрос, может переписать одним 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
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


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

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

Похожие вопросы