D
D
Dmitry2015-03-16 19:04:50
Django
Dmitry, 2015-03-16 19:04:50

How to simplify the query, can rewrite it with one SQL query?

There are several tables. The project has already been written, everything works great, but now you need to display a table with different data, and from different tables. I tried to write all this with one ORM query, then SQL, in the end I decided to collect all the data in views and issue it for rendering into a template.
Here are the tables:

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)

This is how it seems to me not correct, I collect data:
...
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))

As a result I get
  • a list of fields in the header (since there may be a different number from the Element table)
  • user nickname from the main User table
  • the number of occurrences of each element from Element
  • the total sum of all occurrences by weight from Element
  • the date of the last entry in Data

I suspect that even though the implementation is dirty, the performance tends to go down, but how else to collect all the data does not occur to me.
Maybe someone will have ideas.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
Rostislav Grigoriev, 2015-03-17
@crazyzubr

Instead of this

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

It should be like this:
Here's a completely incomprehensible way:
tmp_user.update({
    		'username': get_object_or_none(User, id = user.user.id).username
  	})

When is it possible
Instead of this
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
    		})

It can be easier:
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

In general, you can rewrite all this for a smaller number of requests, but it is inconvenient to write in this text field here. Yes, and you should gradually reach everything yourself, otherwise it can be a disservice))

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question