0

I have a query that outputs data in the following format:

[["W/E 6/11/17", "Carter, J", 40.0],
 ["W/E 6/18/17", "Carter, J", 40.0],
 ["W/E 6/11/17", "Linn, K", 27.0],
 ["W/E 6/18/17", "Linn, K", 27.0],
 ["W/E 6/11/17", "Massey, S", 55.0],
 ["W/E 6/18/17", "Massey, S", 45.0]]

My query:

emp3 = (
    Projectsummaryplannedhours.objects.values(
        'employeename', 'displayval')
    .order_by()
    .filter(businessunit='a')
    .filter(billinggroup__startswith='PLS - Pip')
    .filter(Q(displayval=sunday2)|Q(displayval=sunday))
    .annotate(plannedhours__sum=Sum('plannedhours'))
)

In my template, I'm currently using a for loop, but it returns all items in the list, rather than just the first list of lists.

{% for x in emp3 %}
{{x.employeename}}
{{x.plannedhours__sum}}

What I would like to do is iterate through the list and display Employee: Value for W/E 6/11, Value for W/E 6/18 in a horizontal form.

Model:

class Projectsummaryplannedhours(models.Model):
    number = models.CharField(db_column='Number', max_length=50, blank=True, null=True)  # Field name made lowercase.
    description = models.CharField(db_column='Description', max_length=100, blank=True, null=True)  # Field name made lowercase.
    clientname = models.CharField(db_column='ClientName', max_length=100, blank=True, null=True)  # Field name made lowercase.
    department = models.CharField(db_column='Department', max_length=50, blank=True, null=True)  # Field name made lowercase.
    billinggroup = models.CharField(db_column='BillingGroup', max_length=50, blank=True, null=True)  # Field name made lowercase.
    businessunit = models.CharField(db_column='BusinessUnit', max_length=50, blank=True, null=True)  # Field name made lowercase.
    employeename = models.CharField(db_column='EmployeeName', max_length=50, blank=True, null=True)  # Field name made lowercase.
    displayval = models.CharField(db_column='DisplayVal', max_length=50, blank=True, null=True)  # Field name made lowercase.
    startofweek = models.DateTimeField(db_column='StartOfWeek', blank=True, null=True)  # Field name made lowercase.
    endofweek = models.DateTimeField(db_column='EndOfWeek', blank=True, null=True)  # Field name made lowercase.
    plannedhours = models.DecimalField(db_column='PlannedHours', max_digits=10, decimal_places=5, blank=True, null=True)  # Field name made lowercase.
    rateschedule = models.CharField(db_column='RateSchedule', max_length=50, blank=True, null=True)  # Field name made lowercase.
    classification = models.CharField(db_column='Classification', max_length=50, blank=True, null=True)  # Field name made lowercase.
    dollarsforecast = models.DecimalField(db_column='DollarsForecast', max_digits=10, decimal_places=5, blank=True, null=True)  # Field name made lowercase.
    deleted = models.NullBooleanField(db_column='Deleted')  # Field name made lowercase.
    datelastmodified = models.DateTimeField(db_column='DateLastModified', blank=True, null=True)  # Field name made lowercase.
    datecreated = models.DateTimeField(db_column='DateCreated', blank=True, null=True)  # Field name made lowercase.

Updated Query:

emp3_list = Projectsummaryplannedhours.objects.values('employeename', 'displayval').order_by().filter(businessunit='a').filter(billinggroup__startswith='PLS - Pip').filter(Q(displayval=sunday2)|Q(displayval=sunday)).annotate(plannedhours__sum=Sum('plannedhours'))
emp3 = map(lambda x: {'date': x[0], 'employee_name': x[1], 'planned_hours': x[2]}, emp3_list)

Every query I have tried:

def DesignHubR(request):
#emp1 = Projectsummaryplannedhours.objects.filter(employeename__startswith='Linn').values_list('endofweek').annotate(plannedhours__sum=Sum('plannedhours'))

day = datetime.datetime.today()
start = day - timedelta(days=day.weekday())
s1 = start + timedelta(days=6)
day2 = day + + timedelta(days=7)
start2 = day2 - timedelta(days=day.weekday())
s2 = start2 + timedelta(days=6)
sunday = datetime.datetime.strftime(s1, "W/E %#m/%#d/%y")
sunday2 = datetime.datetime.strftime(s2, "W/E %#m/%#d/%y")
employee = Projectsummaryplannedhours.objects.order_by().values_list('employeename', flat=True).distinct().filter(businessunit='a').filter(billinggroup__startswith='PLS - Pip')
emp1 = Projectsummaryplannedhours.objects.values_list('displayval', 'employeename').filter(businessunit='a').filter(billinggroup__startswith='PLS - Pip').filter(displayval=sunday).annotate(plannedhours__sum=Sum('plannedhours'))
emp4 = Projectsummaryplannedhours.objects.filter(employeename__startswith='Linn').filter(Q(displayval=sunday2)|Q(displayval=sunday)).annotate(plannedhours__sum=Sum('plannedhours'))
emp2 = Projectsummaryplannedhours.objects.values_list('displayval', 'employeename').filter(businessunit='a').filter(billinggroup__startswith='PLS - Pip').filter(Q(displayval=sunday2)|Q(displayval=sunday)).annotate(plannedhours__sum=Sum('plannedhours'))
emp3_list = Projectsummaryplannedhours.objects.values_list('displayval', 'employeename').filter(businessunit='a').filter(billinggroup__startswith='PLS - Pip').filter(Q(displayval=sunday2)|Q(displayval=sunday)).annotate(plannedhours__sum=Sum('plannedhours'))
emp3 = map(lambda x: {'date': x[0], 'employee_name': x[1], 'planned_hours': x[2]}, emp3_list)
context = {'emp1': emp1, 'emp2': emp2, 'sunday2': sunday2, 'employee': employee, 'emp3': emp3, 'emp4': emp4}
return render(request,'department_hub_ple.html', context)
Matt
  • 33
  • 2
  • 7
  • how are you sending your list to the template context? – fixmycode Jun 05 '17 at 17:06
  • 1
    It's unclear to me what you want. Is the query output correct or is it the part you'd like to get right? – Jérôme Jun 05 '17 at 17:07
  • context = {'emp3': emp3} then rendering context – Matt Jun 05 '17 at 17:36
  • @Jérôme the query output is correct unless I need another output to get the desired result in my template. I just posted the query output so the data I'm outputting would be clear. – Matt Jun 05 '17 at 17:37
  • Note that calling `filter()` multiple times ends up filtering for objects that match one or more of the criteria. Is that what you're expecting? https://stackoverflow.com/questions/8164675/chaining-multiple-filter-in-django-is-this-a-bug – Nathan Jones Jun 05 '17 at 22:47
  • @Nathan Jones the data is returning what I expected it to return with those filters. – Matt Jun 06 '17 at 12:51

1 Answers1

0

You can use list indexes in the following way:

{{ x.0 }}

So your template might look like (without any markup or styling):

{% for x in emp3 %}
  {{ x.1 }}
  {{ x.2 }}
{% endfor %}

See Docs on Variables and Lookups

EDIT

If you're looking for a way to use only the list in your list-of-lists, you can chain lookups. The following example would give the second element of the first list.

{{ x.0.1 }}

This probably makes your template harder to read, since it's not very clear what x.0.1 refers to in your context. You might consider changing the data structure of the results, and limiting the data your view returns to just the data your template is going to use.

EDIT 2

To make your template more readable, use a map function convert your list-of-lists back to a list-of-dicts:

emp3_list = [
    ["W/E 6/11/17", "Carter, Jon", 40.0],
    ["W/E 6/18/17", "Carter, Jon", 40.0],
    ["W/E 6/11/17", "Linn, Kenneth", 27.0],
    ["W/E 6/18/17", "Linn, Kenneth", 27.0],
    ["W/E 6/11/17", "Massey, Smiley", 55.0],
    ["W/E 6/18/17", "Massey, Smiley", 45.0]
]
emp3 = map(lambda x: {'date': x[0], 'employee_name': x[1], 'planned_hours': x[2]}, emp3_list)

Your template would then look like this:

{% for x in emp3 %}
    Employee: {{ x.employee_name }}
    Date: {{ x.date }}
    Planned Hours: {{ x.planned_hours }}
{% endfor %}
Nathan Jones
  • 4,904
  • 9
  • 44
  • 70
  • x.0, x.1 doesn't work with .values, only values_list. I have tried using a values list but it's returning both lists, and I want to define it to return only one list. – Matt Jun 05 '17 at 17:35
  • As the docs state, the template engine tries to interpret `x.0` in three different ways: by `dict` key lookup, then `attribute` lookup, then `list`-index. You're right that it won't work for `.values()` because it returns a list of `dict`s. However, that doesn't mean this syntax won't work with list-indexes too. Did you try what I suggested? – Nathan Jones Jun 05 '17 at 17:57
  • Thanks for your response. Yes, I have tried using values_list and values. When using values_list I can use the .0, .1, etc it returns all values for that variable. So I have [[1,2,3],[4,5,6]]. Using x.0 returns 1,4. I would like to return just 1 or just 4. – Matt Jun 05 '17 at 18:06
  • Edited to address your comment. – Nathan Jones Jun 05 '17 at 19:57
  • I see what you mean. So {{x.0.1}} does not work inside a for loop. It's just calling individual parts of the list. – Matt Jun 05 '17 at 21:35
  • I'm confused about what you're after. Do you only want to use the first list in your list-of-lists, or do want to do something with all of your lists? The first example works within a for loop, the second one doesn't. – Nathan Jones Jun 05 '17 at 21:44
  • So in my database I have a row for every hour planned to a project, by week. I want to sum the hours by week, by employee and have those listed out for each employee. – Matt Jun 05 '17 at 22:04
  • I've also hit issues where I receive this error "invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause." when attempting to a variable call in my template. – Matt Jun 05 '17 at 22:12
  • Could you post your `Projectsummaryplannedhours` model code? We could probably make your `annotate()` code return a list of dicts, which will make the template code more readable in the end. – Nathan Jones Jun 05 '17 at 22:51
  • Nathan, thanks again for your help - I have been obsessing over this issue for 2 days... I added the model to the OP. – Matt Jun 06 '17 at 01:27
  • Nathan, thanks for your update. I am receiving a key error when I attempt to map a list-of-dicts – Matt Jun 06 '17 at 16:08
  • What is the error you get, and could you edit your question to include the code you have? – Nathan Jones Jun 06 '17 at 17:31
  • Check bottom of OP for updated query. I'm receiving the following error: Exception Type: KeyError at /app/designhubr/ Exception Value: 0 – Matt Jun 06 '17 at 17:39
  • Are you sure `emp3_list` is still a list-of-lists? If not, please post what `emp3_list`'s value is before the `map()` tries to run. – Nathan Jones Jun 06 '17 at 18:08
  • I changed it back to a values_list and lost the error. I'm getting my data in the same format as I have been though. I want to display my hours by employee in a row, where the columns are hours by week, rather than vertically. Vertically i get duplicate employee names. Maybe I've done a bad job of explaining myself. – Matt Jun 06 '17 at 18:18
  • Oh, you want it grouped by employee. Use [groupby](https://docs.python.org/3.6/library/itertools.html#itertools.groupby) to group by employee name. I'm a bit busy at the moment, but I could provide an example later today if you're still struggling. – Nathan Jones Jun 06 '17 at 18:21
  • Thanks for all your help nathan. I've updated the OP with all the variations of queries I have in my view. – Matt Jun 06 '17 at 18:22
  • Nathan, I got it. I think this puts me on the path I need to be on. Thanks so much. – Matt Jun 06 '17 at 18:41
  • I marked it as answered but my answers aren't registering publicly because of my reputation level. I have another issue I'll need a bit of guidance on (nesting another for statement within the for statement we just created, while getting the employee_name from the above query. I could venmo you some $ for the help. – Matt Jun 06 '17 at 20:07
  • I really appreciate the monetary offer, but that's not necessary :) – Nathan Jones Jun 06 '17 at 23:48
  • Could you possibly take a look here: https://stackoverflow.com/questions/44509521/nested-regroups-django ? – Matt Jun 14 '17 at 13:49
  • I'm thinking a nested regroup might not be possible for what I want to achieve. I am thinking iterating over the query and adding 0 planned hours for employees if they don't have any might be the best route. – Matt Jun 14 '17 at 13:57