I would like to write something in the form of an entry to a particular tournament where the user after clicking on the "join" button is moved to a sheet where the user is asked to enter their name and choose which tournament they want to join. Is it possible to write a conditional instruction that checks if the name of a given tournament is equal to the name of the tournament that the user has chosen and using it to list the users assigned to the given tournament.
my views.py file
def content(request, pk):
tournament = Tournament.objects.get(id=pk)
users = TournamentUsers.objects.all()
return render(request, 'ksm_app2/content.html', {'tournament': tournament, 'users': users})
my models.py file
class Tournament(models.Model):
data = models.DateField(null=True)
tournament_name = models.CharField(max_length=256, null=True)
tournament_creator = models.ForeignKey(Judges, on_delete=models.SET_NULL, null=True)
tournament_info = models.TextField(max_length=10000)
def __str__(self):
return self.tournament_name
class TournamentUsers(models.Model):
user_first_name = models.CharField(max_length=256)
user_last_name = models.CharField(max_length=256)
user_tournament = models.ForeignKey(Tournament, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user_last_name + ' ' + self.user_first_name
{% for user in users %}
{% if user.user_tournament == tournament.tournament_name %}
<p>{{ user.user_first_name }} {{ user.user_last_name }}</p>
{% else %}
<p>no one takes part in this tournament </p>
{% endif %}
{% endfor %}
if u have any idea what i can do i will appreciate that.
.user_tournament is a Torunament, so you check this with:
{% if user.user_tournament == tournament %}
…
{% endif %}
but filtering in the template is not a good idea. It will make the server unresponsive if the number of users keeps growing. You filter in the view with:
from django.shortcuts import get_object_or_404
def content(request, pk):
tournament = get_object_or_404(Tournament, pk=pk)
users = TournamentUsers.objects.filter(user_tournament=tournament)
return render(request, 'ksm_app2/content.html', {'tournament': tournament, 'users': users})
This will perform the filter on the database, which has index structures to do this efficiently. In that case you no longer filter in the template.
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.
Related
I'm trying to make a favorite functionality where an user can add other users as their favorites.
In the View where the profile of an user is shown I have a button that adds an user or removes it if it was already added.
The problem is that I can't pass to the views the user that will be added as a favorite.
models.py
class User(AbstractUser):
is_type1 = models.BooleanField(default=False)
...
class Type1(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
favorite = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, related_name='favorite')
views.py
def FavoriteView(request, pk):
current_user = request.user
Type1.user = current_user.id
buser = Type1.user
Type1.favorite = get_object_or_404(User, id=request.POST.get('username')) # The of the error where I try to add the user being added as a favorite
fuser = Type1.favorite
if Type1.favorite.filter(id=request.user.id).exists():
Type1.favorite.remove(request.user)
else:
Type1.favorite.add(request.user)
return HttpResponseRedirect(reverse('profile-details', kwargs={'username': Type1.favorite}))
class UserView(DetailView):
model = User
...
template_name = 'users/profile-details.html'
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
favorite_connected = get_object_or_404(Type1.favorite, id=self.kwargs['username']) # The of the error where I try to add the user being added as a favorite
favorite = False
if favorite_connected.favorite.filter(id=self.request.user.id).exists():
liked = True
data['user_is_favorite'] = favorite
return data
profile-details.html
...
{% if user.is_authenticated %}
<form action="{% url 'favorite' object.id %}" method="POST">
{% csrf_token %}
{% if user_is_favorite %}
<button type="submit" name="favorite" value="{{object.id}}">Not favorite</button>
{% else %}
<button type="submit" name="favorite" value="{{object.id}}">Favorite</button>
{% endif %}
</form>
{% else %}
Log in to add user to favorites.<br>
{% endif %}
urls.py
path('profile/<str:username>/', UserView.as_view(), name='profile-details'),
path('favorite/<str:username>/', FavoriteView, name="favorite"),
One immediate problem I see is that your URL path wants a string for the username, but your URL for the form gives it the ID of the user, so that'll be an int.
In terms of your error, you're trying to pass a username, but I don't think that'll be in the POST data. However if it was, you should be able to do;
get_object_or_404(User, username=request.POST.get('username'))
However, based on my initial comment, you should probably just get the user by ID like you are doing, but use the PK of the user which is comes with your view;
get_object_or_404(User, id=pk)
You may also come across more errors, because you're assigning an object, if it exists to Type1.favorite and then attempting to do Type1.favorite.filter( which will fail. You can only .filter() on a queryset, not a model instance.
I am working on a Django project. It has two Apps, one for explaining the topic, which has its own model, and views, and the second app is a quiz app, which has its own model and view, which will test the ability / learning of the students on each topics.
The main idea is that for each topic of each book, there will be a quiz to test the ability of the students.
my book explanation model is as follows:
class book_explination(models.Model):
title = models.CharField (max_length = 255)
slug = models.SlugField(max_length= 250, null = True, blank = True, unique= True)
lesson_no = models.CharField (max_length = 255)
book_text = models.TextField (blank=False, null=False)
book_text_explination = models.TextField (blank=False, null=False)
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE, null= True, blank=True)
timestamp = models.DateField(auto_now=False, auto_now_add=True)
def __str__(self):
return self.title
my view for the course model is as follows:
def maths_topics(request):
content_list = book_explination.objects.filter(title = "maths")
return render(request, 'blog/maths_topics.html', {'content_list': content_list})
my url on url.py file is as under:
path('nahwa_meer_topics/', maths_topics, name = 'maths_topics'),
my quiz model is as follows:
class Quiz(models.Model):
title = models.CharField(max_length=255)
book_name = models.CharField(max_length=255)
slug = models.SlugField(blank = True)
topic = models.CharField(max_length=255)
number_of_questions = models.IntegerField()
class Meta:
verbose_name_plural = 'Quizes'
def __str__(self):
return self.title
my view for the quiz app is as follows:
def maths_quiz(request):
maths_quiz = Quiz.objects.filter(book__name = "maths")
return render(request, 'blog/maths_topics.html', {'maths_quiz': maths_quiz})
my django HTML template is as under:
{% for c in content_list %}
<ul class="list-group list-group-horizontal">
{% if c.title == "maths" %}
<li> {{ c.title }}</li>
<li> {{ c.lesson_no }}</li>
<li> {{ c.book_text }}</li>
{% endif %}
</ul>
{%endfor%}
{% for c in maths_quiz %}
<ul class="list-group list-group-horizontal">
{% if c.name == "maths" %}
<li> {{ c.topic }}</li>
<li> {{ c.title }}</li>
{% endif %}
</ul>
{% endfor %}
the HTML template is reflecting the maths book explanation, however, it is not showing the quiz part of the data.
My aim is to show the topics of a book in an html page, and in front of each topic there should be the quiz, related to that topic, bearing in mind that each topic will have it own separate quiz.
Thanks for your support and help. Looking forward for a positive response from your end.
Regards
If I understand this correctly, the maths_quiz variable holds a queryset of Quiz instances. In your template logic, you display a list item, if an instance's name attribute is "maths". However your Quiz model has no name field at all. Could it be that you meant to check the book_name attribute instead?
{% for c in maths_quiz %}
<ul class="list-group list-group-horizontal">
{% if c.book_name == "maths" %}
...
{% endif %}
</ul>
{% endfor %}
Additionally, I think you made an error in your query to begin with:
...
maths_quiz = Quiz.objects.filter(book__name = "maths")
There are two underscores in book__name, but your field has only one:
class Quiz(models.Model):
...
book_name = models.CharField(max_length=255)
Moreover, I just noticed that your whole if condition in the template seems to be redundant since you are doing that exact filtering in your query in the view function before passing the results to the template. So there is really no need to check the book_name again in the template. Every instance in that queryset will have book_name == "maths".
Same goes for the maths_topics view.
Finally, I assume that either the HTML is actually two separate templates or if not, that you are aware that only one of the two sections will ever be displayed depending on the view that is called, maths_topics or maths_quiz, not both.
As a side note: I would suggest using more descriptive variable names, if possible. Seeing as you are working with multiple Quiz instances, I would name the variable something like maths_quizzes and for the iteration I would use a name like quiz instead of c:
def maths_quiz(request):
maths_quizzes = Quiz.objects.filter(book__name = "maths")
return render(request, 'blog/maths_topics.html', {'maths_quizzes': maths_quizzes})
{% for quiz in maths_quizzes %}
...
{% endfor %}
EDIT
OK, now that you explained a bit more, it seems you do think that both querysets should appear somehow. You have two separate views. They render separate responses. If you want both querysets passed to your template data, then you should do that in one view:
def maths_view(request):
content_list = book_explination.objects.filter(title = "maths")
maths_quiz = Quiz.objects.filter(book_name = "maths")
return render(
request,
'blog/maths_topics.html',
{'content_list': content_list, 'maths_quiz': maths_quiz}
)
Then obviously you need to adjust your URL route to point to that view, something like this (for example):
path('yoururlpath/', maths_view, name = 'maths_view')
Also, it seems to me that if your two models are so intimately connected, you may want to consider creating some sort of a relationship between them. Namely, if a quiz is always related to exactly one book, this seems to call for a foreign key relationship from quiz to book.
I mean something like this:
class Quiz(models.Model):
book = ForeignKey(to=book_explination, ...)
...
This would allow you to get all the related objects in the same query.
You can read up on relationships in the Django documentation.
Why my custom template tag doesn't work?
templatetags.py:
from django import template
from ..models import User
register = template.Library()
#register.inclusion_tag('main/post_detail.html', takes_context=True)
def get_user_liked_posts():
request = context['request']
user = User.objects.get(username=request.user.username)
liked_posts = []
for post in user.liked_posts.all():
liked_posts.append(post.name)
return {'liked_posts': liked_posts}
post_detail.html:
{% load static %}
{% load templatetags %}
<nav class="blog-pagination" aria-label="Pagination">
<span id="likes_count">{{ post.likes_count }}</span>
{% if post.name in liked_posts %}
<button id="like_button" class="btn btn-outline-primary btn-primary text-
white">Like</button>
{% else %}
<button id="like_button" class="btn btn-outline-primary">Like</button>
{% endif %}
</nav>
views.py:
class PostDetailView(DetailView):
model = Post
slug_field = 'url'
class LikePostView(View):
def post(self, request, slug):
post = Post.objects.get(id=request.POST['id'])
user = User.objects.get(username=request.user.username)
if request.POST['like'] == 'true':
post.likes_count += 1
user.liked_posts.add(post)
else:
post.likes_count -= 1
user.liked_posts.remove(post)
user.save()
post.save()
return redirect('post_detail', slug)
models.py:
class Post(models.Model):
"""
This is post model
"""
name = models.CharField(max_length=150, blank=False)
article = models.TextField(blank=False)
image = models.ImageField(upload_to='uploads/', blank=True)
likes_count = models.IntegerField(default=0)
url = models.CharField(max_length=150, blank=False)
def get_absolute_url(self):
return reverse('post_detail', kwargs={'slug': self.url})
I want to check if the post is in the liked post of the current user, but it doesn't work.
It doesn't show any errors, it just does nothing.
User in my app must like or unlike posts. In models, I have many to many relationship user with the post. I want to check if the user likes this post
The problem is that you don't even use the template tag, furthermore this is not even needed as you can simply write something like so in the template:
{% if post in request.user.liked_posts.all %}
A Liked post
{% else %}
Not a liked post
{% endif %}
But this is a bit inefficient as we are getting all the posts liked by the user just to check if they like some post. Also if this were in a loop with multiple posts we would be making a query for each post.
Instead we can simply annotate whether the user likes a post in the view itself using an Exists subquery [Django docs] on the through model of the many to many:
from django.db.models import Exists, OuterRef
class PostDetailView(DetailView):
model = Post
slug_field = 'url'
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.annotate(
liked_by_user=Exists(
User.liked_posts.through.objects.filter(
post_id=OuterRef("pk"),
user_id=self.request.user.id
)
)
)
return queryset
Now in the template we can simply write:
{% if post.liked_by_user %}
A Liked post
{% else %}
Not a liked post
{% endif %}
Note: Your way of saving the count similarly can simply be turned into an annotation using the Count aggregation function [Django
docs].
Generally one should not store calculated attributes in a column since
that might lead to inconsistent data when updating and forgetting to update the related count, etc.
I have a model that stores teams and members. I want to check if a requested user is in this team or not. How do i do that?
Model
class TeamPlayer(models.Model):
team = models.ForeignKey(Team, related_name='players', on_delete=models.CASCADE)
player = models.OneToOneField(User, related_name='player', on_delete=models.CASCADE)
approved = models.BooleanField(default=False)
Template
{% if request.user in object.players.all %}
Leave
{% else %}
Join
{% endif %}
View is just simple DetailView.
If you want to do that in the template, just use the teamplayer_set like this:
{% if request.user in object.teamplayer_set.all %}
You have it 1-on-1, so it should be
players = TeamPlayer.object.all()
if request.user.player in players
# Do what you need to
or in template
{% if request.user.player in players %}
provided players is sent to the template
When it's one-on-one, it's always user.player to get related player and player.user for the related user.
In my django website I have pages like 'project_list' and 'project_detail'. Every project has members with different roles (developer, manager, e.t.c.). I want to show different buttons depending on the current user's role in the project in template. I need ideas how to realise it. Lets say something like that in template:
{% if request.user.role_in_the_current_project = 'manager' %}
SOW SOMETHING
{% endif %}
models.py
class Project(models.Model):
name = models.CharField(max_length=250,)
slug = models.SlugField(max_length=250, unique_for_date='publication_date',)
*Other fields*
def get_absolute_url(self):
return reverse('project:project_detail', args=[self.slug])
class Membership (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
ROLE_CHOICES = (
('manager', 'Manager'),
('developer', 'Developer'),
('business_analyst', 'Business analyst'),
('system_analysts', 'System analysts'),
)
role = models.CharField(max_length=20, choices=ROLE_CHOICES,)
view.py
def project_detail(request, slug):
project = get_object_or_404(Project, slug=slug, status='public')
return render(request, 'project/project_detail.html', {'project': project,})
project_detail.html
{% block content %}
<h1>{{ project.name }}</h1>
<p>{{ project.description|linebreaks }}</p>
{%endblock %}
urls.py
urlpatterns = [
url(r'^project/(?P<slug>[-\w]+)/$', project_detail, name='project_detail'),
]
You can use the concept of choices inside a model field and then by using these you can make decisions inside your templates (or to your views) to show appropriate content.
Let me know if you need more info on this.
[EDIT]: So, what you want is to check each time the value of role. Right?
In your views.py write:
project = get_object_or_404(Project, slug=slug, status='public')
memberships = project.membership_set.all()
Then because one project can have many Membership records you should iterate over the memberships to get each time the role.
So, in your template:
{% for membership in memberships %}
{% if membership.role == 'Manager' %} Do stuff here {% endif %}
{% endfor %}
Note that .role will give you back the second value of the ROLE_CHOICES sub-tuple which is capitalized, while the first one is that will be shown in the user if you use the function get_role_display()
Well, after all I found solusion. In view I add:
is_manager = project.membership_set.filter(user=request.user, role='Manager').exists()
Then in template I add:
{% if is_manager %}
<button>Create</button>
{% endif %}