Issue
So, I am trying to filter based on 3 conditions. While I can filter on the two known quantities (the user logged in and if the outcome is a win), I have difficulty filtering on the last condition, which is user-specific information. I know it has to be a simple fix. It's something that probably has to do with the deck's object number, but I can't figure out how to reference those.
Image of what I would like to be shown but with the correct numbers
views.py
def stats(request):
deck_list = Deck.objects.filter(user=request.user)
total_games = Game.objects.filter(user=request.user)
total_wins = Game.objects.filter(user=request.user, outcome='Win')
# WHERE I AM ATTEMPTING TO GET THE DATA
deck_wins = Game.objects.filter(user=request.user, outcome='Win', )
user = User.objects.get(username=request.user)
context = {'deck_list': deck_list,
'user': user,
'total_wins': total_wins,
'total_games': total_games,
'deck_wins': deck_wins,
}
return render(request, 'gametracker_app/stats.html', context=context)
models.py
class Deck(models.Model):
deck = models.CharField(max_length=150)
is_cedh = models.BooleanField(default=False)
user = models.ForeignKey(User,
max_length=10,
on_delete=models.CASCADE,
null=True)
def __str__(self):
return self.deck
class Game(models.Model):
user = models.ForeignKey(User,
max_length=10,
on_delete=models.CASCADE,
null=True)
deck = models.ForeignKey(Deck, on_delete=models.CASCADE, null=True)
wincon = models.ForeignKey(Wincon, on_delete=models.CASCADE, null=True, blank=True)
tournament = models.BooleanField(default=False)
num_players = models.IntegerField(choices=NUM_PLAYERS_CHOICE, default=4)
start_pos = models.CharField(max_length=20, choices=START_POS_CHOICE, default=1)
mull = models.CharField(max_length=20, choices=MULL_CHOICE, default='1st 7')
outcome = models.CharField(max_length=10, choices=OUTCOME_CHOICE, default='Win')
medium = models.CharField(max_length=10, choices=MEDIUM_CHOICE, default='Paper')
date = models.DateField(auto_now=True)
time = models.TimeField(auto_now=True)
Page HTML:
<div class="container-sm p-4">
<div class="card">
<div class="card-body">
{% if deck_list.count == 0 and total_games.count == 0 %}
<p class="">Go play some games and check back!</p>
{% else %}
<h2 class="">{{ user }}'s Stats:</h2>
<br>
<p class="">Decks:</p>
{% for deck in deck_list %}
<p class="">
{{ deck }} {{ deck_wins.count }}
</p>
{% endfor %}
{% endif %}
<br>
<br>
<div class="">
<p class="">Total Games: {{ total_games.count }}</p>
</div>
<div class="">
<p class="">Total Wins: {{ total_wins.count }}</p>
</div>
</div>
</div>
</div>
Solution
Let's tackle the problem you're facing with filtering wins per deck for each user in your Django app. The trick here is to adjust your views.py so that it calculates wins for each deck individually. Also, we'll update the template to display these wins correctly. Here's a more human-like breakdown of what you need to do:
Step 1: Update views.py First up, we need to tweak your stats function in views.py. The goal is to count the number of wins for each deck and pass this information to your template. Here’s how you can do it:
from django.db.models import Count, Q
def stats(request):
# Get the list of decks, and for each deck, count the number of wins
deck_list = Deck.objects.filter(user=request.user).annotate(
wins_count=Count('game', filter=Q(game__outcome='Win', game__user=request.user))
)
# Count total games and wins for the user
total_games = Game.objects.filter(user=request.user).count()
total_wins = Game.objects.filter(user=request.user, outcome='Win').count()
# You can get the user directly from the request
user = request.user
# Prepare your context for the template
context = {
'deck_list': deck_list,
'user': user,
'total_wins': total_wins,
'total_games': total_games,
}
# Render the template with the context
return render(request, 'gametracker_app/stats.html', context=context)
Step 2: Update Your Template Now, in your HTML template, you'll loop through each deck and display the number of wins associated with it:
<div class="container-sm p-4">
<div class="card">
<div class="card-body">
{% if deck_list.count == 0 and total_games == 0 %}
<p>Go play some games and check back!</p>
{% else %}
<h2>{{ user }}'s Stats:</h2>
<p>Decks:</p>
{% for deck in deck_list %}
<p>{{ deck }}: {{ deck.wins_count }} Wins</p>
{% endfor %}
<p>Total Games: {{ total_games }}</p>
<p>Total Wins: {{ total_wins }}</p>
{% endif %}
</div>
</div>
</div>
What Did We Do?
- In views.py, we used Django's annotate() to add a wins_count for each deck. This counts how many times each deck has won.
- In the template, we're simply displaying this count next to each deck.
With these changes, your app should now correctly show the number of wins for each deck on the stats page. It'll be much clearer and user-specific, just the way you wanted!
Answered By - Hirbod Aflaki
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.