I'm trying to display the current lesson amount on the user profile page, but I cannot get it to show up.
Here is my models.py:
class LessonCount(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
lesson_current_amount = models.PositiveIntegerField(default=0, verbose_name='Current Number of Lessons')
def __unicode__(self):
return str(self.user.username)
views.py:
#login_required
def user_profile(request):
user = None
lessoncount = LessonCount.objects.all()
context = {
'user': user,
'lessoncount': lessoncount
}
return render(request, 'account/profile.html', context)
profile.html:
{% extends 'base.html' %}
{% block content %}
<h3 style="color: red;">{{ lessoncount.lesson_current_amount }}</h3>
<h3 style="color: red;">{{ request.user.username }}</h3>
{% endblock %}
Thanks in advance!
You need to loop through the objects:
{% for lesson in lessoncount %}
<h3 style="color: red;">{{ lesson.lesson_current_amount }}</h3>
{% endfor %}
Read more about for loops in the docs.
You need a LessonCount object, but LessonCount.objects.all() is a QuerySet.
Change that line to:
lessoncount = LessonCount.objects.get(user=request.user)
Related
hello iam trying to make Dropdown Menu in Navbar with querysets. I was trying to make it with two querysets send to html template ( "stages","questions") that are related to each other by key (id , stage_id), but i cant figured out why forloops cant work together. My second try was with passing data in json to javascript and make it with js QuerySelector, but django querysets are not JSON serializable. Any suggestions how to make it please ?
views.py
def edit_pages(request, gameid):
stages = Stage.objects.filter(game_id=gameid)
print(stages)
questions = []
for st in stages:
questions = chain(questions,Question.objects.filter(stage_id=st.id))
print(questions)
return render(request, "homeSuperuser/edit_pages.html",{'stages': stages, 'questions': questions})
html
<body>
<div class="topnav">
{% for st in stages %}
<div class="dropdown">
<button class="dropbtn">{{st.stage_name}}</button>
<div class="dropdown-content">
{% for qs in questions %}
{% if qs.stage_id == st.id %}
{{qs.question_name}}
{% endif %}
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</body>
Define a model method as follows
class Stage(models.Model):
name = models.CharField(max_length=128)
def get_questions(self):
return Question.objects.filter(stage=self)
def __str__(self):
return str(self.name)
class Question(models.Model):
stage = models.ForeignKey(Stage, on_delete=models.PROTECT, related_name="questions")
name = models.CharField(max_length=128)
def __str__(self):
return str(self.name)
Now you can loop them in the template as follows
{% for st in stages %}
<div class="dropdown">
<button class="dropbtn">{{st.name}}</button>
<div class="dropdown-content">
{% for qs in st.get_questions %}
{{qs.name}}
{% endfor %}
</div>
</div>
{% endfor %}
I have a django project, where I have two templates: notification.html and base.html. Using get_context_data() method I display the number of answers at the notification.html. I tried to use the same variable in base.html, but it didn't work. I also created CBV that and used get_context_data() to pass the same logic and display it at the base.html, but it doesn't work. How do I display the variable in another template?
I don't how to pass 'answers.count' to the base.html, if base.html doesn't have a view (I created this only now trying to display this variable).
forum.views
class NotificationView(ListView):
model = Answer
template_name = 'forum/notification.html'
# If user visited the notification page - mark all answers as read
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
question = Question.objects.filter(user=user)
answer_read = self.model.objects.filter(question__in=question)
answer_read.update(is_read=True)
return answer_read
def get_context_data(self, **kwargs):
context = super().get_context_data()
user = get_object_or_404(User, username=self.kwargs.get('username'))
question = Question.objects.filter(user=user)
context['answers_all'] = Answer.objects.filter(question__in=question).order_by('-date_posted')
context['answers'] = Answer.objects.filter(question__in=question, is_read=False)
return context
forum/notification.html
{% extends 'main/base.html' %}
{% block content %}
<div class="container">
<b>УNotofocations: {{ answers.count }}</b>
{% for answer in answers_all %}
<div class="card mb-3 mt-2">
<div class="card-body">
Ответ на вопрос: {{ answer.question }}
<p>{{ answer.detail }}</p>
{{ answer.user.username }}
<span class="ml-4">{{ answer.date_posted|naturalday }}</span>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
main.views
class BaseView(TemplateView):
template_name = 'main/base.html'
def get_context_data(self, **kwargs):
context = super().get_context_data()
user = get_object_or_404(User, username=self.kwargs.get('username'))
question = Question.objects.filter(user=user)
context['answers'] = Answer.objects.filter(question__in=question)
return context
main/base.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
{% if user.is_authenticated %}
{% if answers.count < 1 %}
<i class="fas fa-bell"></i>
{% else %}
<i class="fas fa-bell"></i><span class="pending">{{ answers.count }}</span>
{% endif %}
{% endif %}
</head>
</html>
guess you are only missing the build-in template tags
in forum/notification.html
{% extends "base.html" %}
in main/base.html
{% block content %}{% endblock %}
https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#extends
https://docs.djangoproject.com/en/4.1/ref/templates/language/#template-inheritance
Finally, I solved this problem. The idea was to display the variable from context_data at base.html. As get_context_data didn't help, I found the solution in Django documentation. The solution was so easy, I hope to save time for other learners if they got the same problem.
I used context_processors.py to pass extra information and display it on the page. My step were:
Created a context_processors.py file in my app directory.
Created a function def get_notifications_number(request) where I filter what I want to display at base.html and returned return {'answers': answers}
Finally, I registered the file in Django TEMPLATES 'my_app.context_processors.get_notifications_number'.
One of functionality in my training project:
subscribe to the news by check-box and e-mail.
Send newsletter daily.
The user can unsubscribe from the mailing list in his profile by unchecking the checkbox.
It so happened that first I set up a daily newsletter for users who have booleanfield = true.
For it I marked the checkboxes in the admin panel. It works.
Now it is necessary to add the checkbox and the mail field to the news page.
I'm stuck on the simplest. Tired and confused.
Please help me place a checkbox and a mail box with a send button on the news page
models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
hr = models.BooleanField(default=False)
subscribed_for_mailings = models.BooleanField(default=False)
subscription_email = models.EmailField(default="")
def __str__(self):
return str(self.user)
Forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscription_email', 'subscribed_for_mailings', )
widgets = {
'subscription_email': forms.EmailInput(attrs={"placeholder": "Your Email..."}),
'subscribed_for_mailings': forms.CheckboxInput,
}
views.py
def all_news(request):
today = date.today()
today_news = models.TopNews.objects.filter(created__gte=today)
return render(request, "news.html",
{'today_news': today_news})
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
mailing_form.save()
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
urls.py
...
path('news/', views.all_news, name='all_news'),
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1>
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<p>
{{ news.created }}
</p>
<hr>
{% endfor %}
<h4>I want to receive news by mail</h4>
<form action="." method="post">
{{ mailing_form.as_p }}
{% csrf_token %}
<label>
<input type="submit" value="Subscribe">
</label>
</form>
{% endblock %}
The page displays a list of news and only the "send" button. There is no check-box and a field for mail
enter image description here
Finally I realized this functionality in a different way:
forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscribed_for_mailings', 'subscription_email', )
views.py
#login_required
def mailing_news(request):
if request.method == "POST":
mailing_form = forms.MailingForm(request.POST,
instance=request.user.profile,
)
if mailing_form.is_valid():
mailing_news = mailing_form.save(commit=False)
mailing_news.subscribed_for_mailings = mailing_news.subscribed_for_mailings
mailing_news.subscription_email = mailing_news.subscription_email
mailing_news.save()
return render(request, "subscribe_complete.html",
{"mailing_news": mailing_news})
else:
mailing_form = forms.MailingForm()
return render(request, 'subscribe.html', {"mailing_form": mailing_form})
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
urls.py
...
path('subscribe/', views.mailing_news, name='subscribe')
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
subscribe.html
{% extends 'base.html' %}
{% block title %}
Subscribe
{% endblock %}
{% block body %}
<form action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ mailing_news.as_p }}
{% if user.profile.subscribed_for_mailings is True %}
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings" checked="">
If you don't want to receive emails anymore, uncheck
<br>
Subscription email: <input type="email" name="subscription_email" value={{ user.profile.subscription_email }} class="vTextField" maxlength="254" id="id_subscription_email">
{% else %}
<label>
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings">
I want to subscribe for mailing news
</label>
<p><label>
Send news on my email:
<input type="email" name="subscription_email" class="vTextField" maxlength="254" id="id_subscription_email">
</label></p>
{% endif %}
<p><input type="submit" value="Update"></p>
</form>
{% endblock %}
subscribe_complete.html
{% extends 'base.html' %}
{% block title %}
Subscribing complete
{% endblock %}
{% block body %}
<h3>Hi {{ user.username }}</h3>
Thanks for subscribing.
You will receive daily news by email: {{ user.profile.subscription_email }}
{% endblock %}
you need to change subscribed_for_mailings in mailing news, like this
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
profile = mailing_form.save(commit=False) ####
profile.subscribed_for_mailings = mailing_form.cleaned_data.get('subscribed_for_mailings') ####
profile.subscription_email = mailing_form.cleaned_data.get('subscription_email') ####
profile.save() #### new_line
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
you can change in cleaned_data.get('....')
this is models.py
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField()
date = models.DateTimeField(default=timezone.now)
def write(self):
self.date = timezone.now()
self.save()
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey('humorge.post', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=100)
content = models.TextField()
date = models.DateTimeField(default=timezone.now)
def add_coment(self):
self.date = timezone.now()
self.save()
def __str__(self):
return self.content
and this is views.py
def mainpage(request):
return render(request, 'index.html')
def post(request):
datas = Post.objects.order_by('-date')
comments = Comment.objects.all()
return render(request, 'post.html', {'datas': datas, 'comments': comments})
and this is template
{% extends 'layout.html' %}
{% block main %}
<div class="container">
{% for data in datas %}
<div class="row">
<div class="col s12 m7">
<div class="card">
<div class="card-image">
<img src="#">
<span class="card-title">{{ data.title }}</span>
</div>
<div class="card-content">
<p>{{ data.content }}</p>
</div>
<div class="card-action">
<p>{{ data.date }}</p>
</div>
<div class="card-action">
{% for comment in comments %}
{% if comment.post == data.title %}
{{ comment.date }}<br>
<strong>{{ comment.author }}</strong>
<p>{{ comment.content }}</p>
{% endif %}
{% empty %}
<p>There is no comments</p>
{% endfor %}
</div>
</div>
</div>
</div>
{% empty %}
<p>there is no posts</p>
{% endfor %}
</div>
{% endblock %}
I want to display posts and comments
when I try to have two posts and each post has one comments
it shows like each posts has two comments
so I added {% if comment.post == data.title %} in the template
but it shows nothing
I tried to find answers on google, youtube, some tutorial page....
but what I found was just how to add comments on posts..
or displaying post and comment but actually one post one comment
You don't need to query list of comments in you views, you need just posts:
def post(request):
datas = Post.objects.order_by('-date')
return render(request, 'post.html', {'datas': datas})
And in template you can then do something like this:
{% block main %}
<div class="container">
{% for data in datas %}
...
<div class="card-action">
{% for comment in data.comments.all %} // Gives list of all comments for the current post ie. data
{{ comment.date }}<br>
<strong>{{ comment.author }}</strong>
<p>{{ comment.content }}</p>
{% empty %}
<p>There is no comments</p>
{% endfor %}
</div>
{% empty %}
<p>there is no posts</p>
{% endfor %}
</div>
...
{% endblock %}
Btw the thing that's wrong with the if condition in your template is that you are doing {% if comment.post == data.title %} but commpent.post is an object of model Post and post.title is string, so they are never equal. What you need to do is {% if comment.post == data %} or {% if comment.post.title == data.title %}
In your post view, instead of:
comment = Comment.objects.all()
which will fetch all the comments irrespective of the post it belongs to,
do this:
comment = datas.comments.all()
where the 'comments' is the related_name declared in the post field of the Comment model.
I am using Django, PyCharm 2018.3.7, Python 3.7, and Postgres.
Unfortunately, I do not understand how to display on one screenpage (Django form) the results for 2 separate querysets that need the same ID passed by a dynamic filter request (GET). There is a table/model (ASSIGNMENTS) with a One-To-Many relationship to another table/model (PRODUCTS). The ID being passed is the ASSIGNMENTS.ID, which is the PK of ASSIGNMENTS and the FK of PRODUCTS.
I am not trying to join these 2 querysets. I need the user to see the information for the ASSIGNMENT first and then below I want them to see all of the PRODUCTS that belong to that ASSIGNMENT.
I do not need to update/create data, so no POST is needed. Only want to retrieve, GET, data that exists.
Below are the code for models.py, views.py, and templates. It works perfect with just ASSIGNMENTS.
MODELS.PY
class Assignments(models.Model):
id = models.DecimalField(db_column='ID', primary_key=True, max_digits=9, decimal_places=0)
name = models.CharField(db_column='NAME', unique=True, max_length=40)
def __str__(self):
return self.name + ' ' + '(' + '#' + str(self.id) + ')'
class Meta:
ordering = 'name',
db_table = 'ASSIGNMENTS'
class Products(models.Model):
id = models.DecimalField(db_column='ID', primary_key=True, max_digits=11, decimal_places=0)
assignment = models.ForeignKey(Assignments, models.DO_NOTHING, related_name='productsfor_assignment', db_column='ASSIGNMENT_ID', blank=True, null=True)
name = models.CharField(db_column='NAME', max_length=80)
def __str__(self):
return self.name + ' ' + '(' + '#' + str(self.id) + ')'
class Meta:
ordering = 'name',
db_table = 'PRODUCTS'
VIEWS.PY
def search_form(request):
return render(request, 'assignments/search_form.html')
def search(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
assign = Assignments.objects.filter(id__icontains=q)
return render(request, 'assignments/search_results.html',
{'AssignmentsResults': assign, 'query': q})
else:
# if the query is empty, render the 'search_form html' template again.
# display an error message in that template. So, pass a template variable.
# 'search_form html' will check for the 'error' variable
return render(request, 'assignments/search_form.html', {'error': True})
TEMPLATE 'search_form.html'
{% extends "base.html" %}
{% block content %}
<br><br>
<h1> Assignment ID Search Form </h1>
<br><br>
{% if error %}
<p style="color: red;">Please submit a search term.</p>
{% endif %}
<form action="/search/" method="get">
<input type="text" name="q" placeholder="Enter ID here ...">
<input type="submit" value="Search">
</form>
<p>
Page last updated: {{ last_updated|date:'D d F Y' }}
</p>
{% endblock content %}
TEMPLATE 'search_results.html'
{% extends "base.html" %}
{% block content %}
<br><br>
<h1> Assignment ID Search Results</h1>
<p>You searched for: <strong>{{ query }}</strong></p>
{% if AssignmentsResults %}
<ul>
{% for assignments in AssignmentsResults %}
<li>
{{ assignments.id }}, {{ assignments.name }}
</li>
{% endfor %}
</ul>
{% else %}
<p>No assignments matched your search criteria.</p>
{% endif %}
{% endblock content %}
This is what I finally put together to include Products (shown below in the failed views.py and template). But, it does not work.
This was the FAILED VIEWS.PY
def search_form(request):
return render(request, 'assignments/search_form.html')
def search(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
assign = Assignments.objects.filter(id__icontains=q)
prod = Products.objects.filter(assignment__icontains=q)
return render(request, 'assignments/search_results.html',
{'AssignmentsResults': assign, 'query': q})
return render(request, 'assignments/search_results.html',
'ProductsResults': prod, 'query': q)
else:
# if the query is empty, render the 'search_form html' template again.
# display an error message in that template. So, pass a template variable.
# 'search_form html' will check for the 'error' variable
return render(request, 'assignments/search_form.html', {'error': True})
This was the FAILED TEMPLATE CODE 'search_results.html
{% extends "base.html" %}
{% block content %}
<br><br>
<h1> Assignment ID Search Results</h1>
<p>You searched for: <strong>{{ query }}</strong></p>
{% if AssignmentsResults %}
<ul>
{% for assignments in AssignmentsResults %}
<li>
{{ assignments.id }}, {{ assignments.name }}
</li>
{% endfor %}
</ul>
<p> These are the Products attached to the Assignment.</p>
{% if ProductsResults %}
<ul>
{% for products in ProductsResults %}
<li>
{{ products.assignment }}, {{ products.name }}
</li>
{% endfor %}
</ul>
{% else %}
<p> No products for this assignment exist.</p>
{% endif %}
{% else %}
<p>No assignments matched your search criteria.</p>
{% endif %}
{% endblock content %}
I have created the project by following 'Build a website with Django 2, updated for Django 2.2' by Nigel George. I have looked at several youtube instructional videos and read questions on stackoverflow. (These are only a couple.)
How to combine two or more querysets in a Django view?
Displaying a series of inline forms for a queryset of Django models
Django: Add queryset to inlineformsets
Django nested QuerySets
InlineFormSet with queryset of different model
However, none of them have been able to help me with my problem of presenting 2 separate queryset results on one form.
I'd certainly appreciate any suggestions and help provided.
Thanks
Okay, let's see. If you just want to display the information that it seems to be intended in search_results.html, I suggest you to refactor a little bit your query as follows.
(I will try to clean out the weird things (for example having two consecutive return statements) as much as I can to illustrate my point)
views.py:
from django.shortcuts import render, redirect
from django.urls import reverse
def search(request):
q = request.GET.get('q', None)
if q:
assignments_qs = Assignments.objects.filter(id__icontains=q) \
.prefetch_related('productsfor_assignment')
context_data = {'assignments': assignments_qs}
return render(request, 'assignments/search_results.html', context_data)
else:
return redirect(reverse('search_form', kwargs={'error': True}))
def search_form(request, error=False):
return render(request, 'assignments/search_form.html', {'error': error})
search_results.html
{% if assignments %}
<ul>
{% for assignment in assignments %}
<li>
{{ assignment.id }}, {{ assignment.name }}
</li>
{% if assignment.productsfor_assignment.exists %}
<p> These are the Products attached to the Assignment.</p>
<ul>
{% for product in assignment.productsfor_assignment.all %}
<li>
{{ product.assignment }}, {{ product.name }}
</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</ul>
{% else %}
<p>No assignments matched your search criteria.</p>
{% endif %}
I think this is the best and the most similar way to achieve what you want considering what you currently have.