Problem with looping through Users

I have create and application that keeps track of shoots scores. I have a scoring application that works fine. it use the following models Score

from django.conf import settings
from django.db import models

rifle_type_choices = {(“B”, “B”), (“S”, “S”)}
optic_type_choices = {(“O”, “O”), (“S”, “S”)}
range_distance_choices = {(“50”, “50”), (“100”, “100”)}

class Scores(models.Model):
date = models.DateField()
match_score = models.IntegerField()
xcount = models.IntegerField()
rilfe_type = models.CharField(max_length=1, choices = rifle_type_choices, default = “B”)
optic_type = models.CharField(max_length=1, choices = optic_type_choices, default = “O”)
range_distance = models.CharField(max_length=3,choices = range_distance_choices, default = “100” )
username = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)

  def __str__(self):
      return f' {self.username} {self.date}'    

I create a App for averaging the score and here is the View

from django.http import HttpResponse
from django.template import loader
from scores.models import Scores
from django.db.models import Avg

def index(request):
template = loader.get_template(“average.html”);

context = {

    'avg50': Scores.objects.filter(username=myusername,range_distance="50").aggregate(Avg("match_score")),
    'avg100': Scores.objects.filter(username=myusername, range_distance="100").aggregate(Avg("match_score")),
    'scores_list': Scores.objects.values('username')
}

return HttpResponse(template.render(context, request))

Here is the average template

{% extends “base.html” %}
{% load static %}

{% block content %}

    body {
        background-color: lightblue;
        text-align: left;
    }

    table, th, td {

        border: 1px solid black;
        width: 15em;
        table-layout: fixed;
        border-collapse: collapse;
        text-align: center;
        border: black solid 0.1em;
    }
</style>

Indviual Average Score "Not working Yet

Username 50 Yard Avg 100 Yard Avg

{%for i in myusername%}



{%endfor%}
{{i.user}} {{i.avg50}} {{i.avg100 }}

{% endblock content %}

I am having a problem figuring out how to loop through the user so that I can figure there average.

any help would be great

thank you

Ed

You want your “base model” for your query to be on User then.

You can then annotate the scores for each user.

e.g.
user_list = User.objects.annotate(avg50=..., avg100=...)

If you’re not familiar with annotations, start with the docs at Aggregation | Django documentation | Django. Pay particular attention to the cheat sheet to see some examples, some of which are very close to what you’re looking to do.

1 Like

Ken

I have read the doc several time.
I am getting this error

Here is the update veiw

average/views.py

from scores.models import Scores
from django.db.models import Q, Avg

def index(self):
user_list = Scores.objects.annotate(“match_score”).filter(range_distance=“50”),

return (user_list)

Here is the error
QuerySet.annotate() received non-expression(s): match_score.

Match_score is a integer

Thank you for the help

Ed

Pulling what I think is the best example from the cheat sheet:

>>> above_5 = Count("book", filter=Q(book__rating__gt=5))
>>> below_5 = Count("book", filter=Q(book__rating__lte=5))
>>> pubs = Publisher.objects.annotate(below_5=below_5).annotate(above_5=above_5)

I think you’re going to end up with something like:

avg50=Avg('scores__match_score', filter=Q(scores__range_distance="50"))
avg100=Avg('scores__match_score', filter=Q(scores__range_distance="100"))
user_list = User.objects.annotate(avg50=avg50, avg100=avg100)

Note: I’m winging this, there may be an error or 10 here - but it should be enough to get you started.

Good Morining Ken

Thank you for the help. I change it to this

from django.http import HttpResponse
from django.template import loader
from scores.models import Scores
from django.db.models import Q, Avg


def index(request):
    template = loader.get_template('average.html');

    avg50 = Scores.match_score, filter = Q(range_distance="50"),

    scores_list = Scores.objects.annotate(avg50=avg50)


    return HttpResponse(template.render(avg50, request))

But I am getting this

Not sure what they are trying to tell me

not enough values to unpack (expected 2, got 1)

When you’re posting code here, enclose the code between lines of three backtick - ` characters. This means you’ll have a line of ```, then your code, then another line of ```. This forces the forum software to keep you code properly formatted. (I’ve taken the liberty of fixing your previous post for you.)

I’m sorry, I’m not understanding what you’re trying to do with that view - or what the results are that you’re looking to get. What are you trying to do here and how does this relate to everything we’ve been talking about previously?

(Nor do I understand why you’re using get_template and template.render rather than the render shortcut, but that’s just a style issue and not really a problem.)

Ken

Sorry about the formatting.

So I am still working on trying to get the avg to work for the scores that you been helping me with.

I have been trying you your last response.

so I change the average view to this and when I click on the average option I get this error

Is it trying to say I am not passing it enough variables.

I want to thank you again for all your help. I have read four books and I am retired and this is fun…

Ed

ValueError at /avg

not enough values to unpack (expected 2, got 1)

Request Method: GET
Request URL: http://127.0.0.1:8000/avg
Django Version: 4.2.7
Exception Type: ValueError
Exception Value:

not enough values to unpack (expected 2, got 1)

Exception Location: /Users/ejmmanning/Desktop/code/match-score/avg_scores/views.py, line 10, in index
Raised during: avg_scores.views.index
Python Executable: /Users/ejmmanning/Desktop/code/match-score/.venv/bin/python3
Python Version: 3.11.1
Python Path:

['/Users/ejmmanning/Desktop/code/match-score',
 '/Library/Frameworks/Python.framework/Versions/3.11/lib/python311.zip',
 '/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11',
 '/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload',
 '/Users/ejmmanning/Desktop/code/match-score/.venv/lib/python3.11/site-packages']

Server time: Mon, 27 Nov 2023 15:44:33 +0000

from django.http import HttpResponse
from django.template import loader
from scores.models import Scores
from django.db.models import Q, Avg

def index(request):
    template = loader.get_template('average.html');

    avg50 = Scores.match_score, filter = Q(range_distance="50"),

    scores_list = Scores.objects.annotate(avg50=avg50)

    return HttpResponse(template.render(avg50, request))

But what you’ve posted here for this view isn’t anything at all like the query example I showed at #4, nor does it match what was discussed at #2. (Also, the parameter to the template.render function is a context. See The Django template language: for Python programmers | Django documentation | Django)

I try what you were say and I could not get it to work. I am just trying to get the average score for each shooter.

Thank again

Ken

I went back to what you sent me but I am getting a
error
TypeError at /avg

context must be a dict rather than Avg.

where can i figure out what this means

Thanks

— from django.http import HttpResponse
—from django.template import loader
—from scores.models import Scores
—from django.db.models import Avg, Q

—def index(request):
—template = loader.get_template(‘average.html’);

—avg50=Avg(‘scores_match_score’,filter= Q(scores_range_distance=‘50’))

—scores_list = Scores.objects.values(‘username’)

—return HttpResponse(template.render(avg50, request))

To repeat from post #6

When you’re posting code here, enclose the code between lines of three backtick - ` characters. This means you’ll have a line of ```, then your code, then another line of ```. This forces the forum software to keep you code properly formatted.

Also, you’re still trying to base you query on Scores instead of User as I pointed out earlier. If you want the scores for each user, you are going to want to annotate the average on the User.

Read the docs I referenced at post #8

Sorry for all the trouble.

I user a custom user should I import that

AUTH_USER_MODEL = "accounts.CustomUser"

Ken

when I use CustomUser

I get this error

FieldError at /avg

Cannot resolve keyword 'score_match_score' into field. Choices are: age, article, date_joined, email, first_name, groups, id, is_active, is_staff, is_superuser, last_login, last_name, logentry, password, phone_number, scores, user_permissions, username

Thank you

Ed

from django.http import HttpResponse

from django.template import loader
from scores.models import Scores
from accounts.models import CustomUser
from django.db.models import Avg, Q

def index(request):
 template = loader.get_template('average.html');

 avg50=Avg('match_score',filter=Q(range_distance='50'))

 scores_list = CustomUser.objects.annotate(avg50=avg50)

 return HttpResponse(template.render(avg50))

Ken

I have it working with one user but I am trying to figure out how to get it to run with all the users.

from django.http import HttpResponse
from django.template import loader
from scores.models import Scores
accounts.models import CustomUser
django.db.models import Avg, Q
django.db.models.functions import Concat
index(request):

```context = {```
```'avg50':  Scores.objects.filter(username= "1",  range_distance="50").aggregate(Avg("match_score")),```
```'avg100': Scores.objects.filter(username='1', range_distance="100").aggregate(Avg("match_score")),```
         }
```return HttpResponse(template.render(context, request))```



As you can see it works for the username I hard code in the filter 

![Screen Shot 2023-11-27 at 19.30.20|690x134](upload://ax7vWPfA0S5kD08brvlIqBXOph8.png)

In the Django shell, issue the queries exactly as I show at Post #4, replacing User.objects... with CustomUser.objects... as appropriate. (Not the samples from the doc page, but the three parts written for you.)

Then, if you have a specific ID that you know what the values are supposed to be:

a_user = user_list.get(id=<whatever>)
print(a_user.id, a_user.avg50, a_user.avg100)

and let me know if the average is what you expect it to be.

Side note: When using the three backticks to fence off your code, you use one line of ``` before the code and one line of ``` after the code. Those fences must be on lines by themselves and are used to surround an entire block of code, not on individual lines. If you need to mark some text that is all on one line as preformatted, use a single backtick as a marker: It produces output like this..

Good morning Ken

I get this error

Good Morining Ken

I have the code that will give me the right answer for 1 hard coded user. What i can’t figure out is how to use a variable for username so that it will do the average for all users.

Here is the code

from django.template import loader
from scores.models import Scores
from accounts.models import CustomUser
from django.db.models import Avg, Q


def index(request):
  template = loader.get_template('average.html');

  context = {

    'avg50': Scores.objects.filter(username='1', range_distance="50").aggregate(Avg("match_score")),
    'avg100': Scores.objects.filter(username='1', range_distance="100").aggregate(Avg("match_score")),

  }

  return HttpResponse(template.render(context, request)) ```

That is precisely what I have given you.

Ken

do you know of a good tutor that I can pay to help me out

Thanks

No, I’m sorry I don’t.