Im new to programming and I looking if there is there a way that I can include a template inside other template. Im working on a project that I want to display on the same page a content of a certain topic and flashcards to test my knowledge of this topic, and Im stuck when trying to display my cards on the same page (I could only make it work using another url). Here is what I have so far:
models.py:
class Topic(models.Model):
author = models.ForeignKey(
User, related_name="topic", on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=100)
body = RichTextUploadingField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(max_length=120)
class Meta:
ordering = ["title"]
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('topic:topic-detail', kwargs={
"topic_slug": self.slug,})
class Deck(models.Model):
deckTopic = models.ForeignKey(
Topic, null=True, blank=True, on_delete=models.CASCADE)
description = models.CharField(max_length=510, null=False, blank=True)
is_active = models.BooleanField(default=False)
def __str__(self):
return self.description
def get_number_of_cards(self):
'''
Returns the number of cards in the decks related card_set
'''
return self.card_set.count()
get_number_of_cards.short_description = 'Card Count'
class Card(models.Model):
parentDeck = models.ForeignKey(Deck, on_delete=models.CASCADE)
front = models.TextField()
back = models.TextField()
def __str__(self):
return self.front
def has_prev_card(self):
'''
Returns true if card is not thee first card in the deck.
'''
first_card_in_deck = self.parentDeck.card_set.first()
if self == first_card_in_deck:
return False
return True
def get_prev_card(self):
'''
Return previous card in deck
'''
return self.parentDeck.card_set.filter(id__lt=self.id).last()
def has_next_card(self):
'''
Returns true if card is not the last card in the deck.
'''
last_card_in_deck = self.parentDeck.card_set.last()
if self == last_card_in_deck:
return False
return True
def get_next_card(self):
'''
Return next card in deck
'''
return self.parentDeck.card_set.filter(id__gt=self.id).first()
views.py:
class TopicDetailView(DetailView):
model = Topic
def viewDeck(request, deck_id):
'''
Gets the deck from the database.
Return first card in deck unless card_id is specified in url.
'''
deck_obj = get_object_or_404(Deck, id=deck_id)
card_list = deck_obj.card_set.all()
card_obj = card_list.first()
if request.method == 'GET' and 'card' in request.GET:
card_obj = get_object_or_404(Card, id=request.GET['card'])
context = {
'deck_obj': deck_obj,
'card_obj': card_obj,
}
return render(request, 'topic/viewDeck.html', context)
topic_detail.html:
{% extends 'base.html' %}
{% block content %}
<div class="topic-title">
<h5 class="mb-0">
{{object.title}}
</h5>
</div>
<div class="topic-body">
<p class="mb-0">
{{object.body}}
</p>
</div>
<!--Here is where I want to include the flashcard--!>
<div class="topic-deck">
{% for deck in object.deck_set.all %}
{{deck.description}}
Flashcard
{% endfor %}
</div>
{% endblock %}
viewDeck.html:
{% extends 'base.html' %}
{% block content %}
<div class="deck-container">
<div class="deck-header">
<div class="deck-header-title">
<h1>{{deck_obj}}</h1>
</div>
<div class="deck-header-actions">
<p>Return to Topic</p>
</div>
</div>
<hr>
{% if card_obj %}
<div class="notecard">
<div class="notecard-nav text-center">
{% if card_obj.has_prev_card %}
<a href="{% url 'topic:viewDeck' deck_obj.id %}?card=
{{card_obj.get_prev_card.id}}">Prev</a>
{% endif %}
{% if card_obj.has_next_card %}
<a href="{% url 'topic:viewDeck' deck_obj.id %}?card=
{{card_obj.get_next_card.id}}">Next</a>
{% endif %}
</div>
<div class="notecard-front">
<p class="text-center">Front</p>
<p>{{card_obj.front}}</p>
</div>
<div class="notecard-back">
<p class="text-center">Back</p>
<p>{{card_obj.back}}</p>
</div>
</div>
{% else %}
<p>No card found.</p>
{% endif %}
</div>
{% endblock %}
Is there a way to see deckView inside topic_detail.html? Sorry if I didn't made myself clear.
Update:
I tried inserting {% include 'viewDeck.html' %} as passing the context deck_obj, card_list and card_obj to topic_detail.html, but it gives me this error: NameError: name 'deck_id' is not defined. How can I fix this?
Thank you.
Did you build the url correctly ?
To be able to pass the deck_id like you did in your view, you have to tell your url that you want to pass some data in, by writing something like this in your urls.py :
from name_of_your_app import views
url(r'deck/(?P<deck_id>\d+)/$', views.viewDeck , name='name_of_you_url'),
(?P<deck_id>\d+) is the important part, as it indicates that you will receive a numerical data which can be called with the name "deck_id".
Related
I have two models, ProjectNotes and ProjectNoteComments. ProjectNoteComments are related to ProjectNotes via a foreign key. I want to display the number of comments each note has on a listview. I am just learning Django and so far I have not been able to figure out how to retrieve and display the comment count.
My view:
(I do import count)
class ProjectNotesList(ListView):
model = ProjectNotes
template_name = 'company_accounts/project_notes.html'
comments = ProjectNotes.comments
def related_project(self, **kwargs):
project = get_object_or_404(Project, id=self.kwargs.get('pk'))
notes = ProjectNotes.objects.all
return notes
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['project'] = get_object_or_404(Project, id=self.kwargs.get('pk'))
return context
commentscount = ProjectNotes.objects.annotate(num_comments=Count('comments'))
My template:
{% extends 'base.html' %}
{% block content %}
<div class="section-container container">
<h1>Notes for {{ project }}</h1>
{% if project.notes.all %}
{% for note in project.notes.all %}
<div class ="projectnotes-entry">
<div class="col-sm-8">
<div class="row-sm-6">
<div class="card mb-2">
<div class="card-body">
<div class="card-title">{{ note.title }}</div>
<div class="card-text">{{ note.body | safe | truncatewords:"20"|linebreaks }}
read more</div>
</div>
</div>
</div>
</div>
</div>
<h2>comments count</h2>
{{ commentscount }}
{% endfor %}
{% else %}
<p>No notes have been have been added yet.</p>
{% endif %}
</div>
{% endblock content %}
The models:
class ProjectNotes(models.Model):
title = models.CharField(max_length=200)
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
project = models.ForeignKey(Project, default=0, blank=True, on_delete=models.CASCADE, related_name='notes')
def __str__(self):
return self.title
class ProjectNoteComments(models.Model):
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
projectnote = models.ForeignKey(ProjectNotes, default=0, blank=True, on_delete=models.CASCADE, related_name='comments')
Short version:
{{ note.comments.all.count }} # possibly works also without 'all' but can't check right now
I've just answered similar problem with simple explanation of relationships.
https://stackoverflow.com/a/70955851/12775662
Read official docs, it's really rewarding. https://docs.djangoproject.com/en/4.0/topics/db/models/#relationships
I have multiple users in my project
my models.py file is
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
class Teacher(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,related_name='Teacher')
name = models.CharField(max_length=250)
subject_name = models.CharField(max_length=250)
email = models.EmailField(max_length=254)
phone = models.IntegerField()
teacher_profile_pic = models.ImageField(upload_to="classroom/teacher_profile_pic",blank=True)
def __str__(self):
return self.name
class Announcement(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
def __str__(self):
return self.title
If the logged in user is a teacher it is allowed to create an announcement
Now i want that only the teacher who posted the announcement should be able to see the delete button
My html file is
{% extends "classroom/base.html" %}
{% block content %}
<h1>Announcements</h1>
{% for announcement in announcements %}
<!-- starting loop (posts is keyword from view) -->
<div style="border-style: solid;">
{% if object.teacher.id == request.teacher %}
<div>
Delete
</div>
{% endif %}
<a class="mr-2">Posted by: {{ announcement.teacher }}</a>
<h2><a class="article-title">{{ announcement.title }}</a></h2>
<p class="article-content">{{ announcement.content}}</p>
</div>
{% endfor %}
{% endblock content %}
the if statement is supposed to be true if logged in teacher is the teacher who originally posted it. However the delete button is visible for every announcement
my views.py has
class AnnouncementListView(ListView):
context = {
'announcements' : Announcement.objects.all()
}
model = Announcement
template_name = 'classroom/all_announcements.html'
context_object_name = 'announcements'
Try using this.
{% if announcement.teacher.user == request.user %}
<div>
Delete
</div>
{% endif %}
Your models are a bit "unconventional".
However, this should work:
{% if announcement.teacher.user == request.user %}
...
{% endif %}
Model
class Category(models.Model):
class Meta():
verbose_name_plural = "Categories"
cat_name = models.CharField(max_length=50)
description = models.TextField()
def get_forums(self):
get_forum = Forum.objects.filter(category=self)
return get_forum
def __str__(self):
return f"{self.cat_name}"
class Forum(models.Model):
class Meta():
verbose_name_plural = "Forums"
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="forums")
parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
forum_name = models.CharField(max_length=50)
description = models.TextField()
def __str__(self):
return f"{self.forum_name}"
Views
class Home(ListView):
model = Category
template_name = 'forums/index.html'
context_object_name = 'category'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['cat'] = Category.objects.all()
return context
HTML
{% block content %}
{% for cat in category %}
<div class="row">
<div class="bg-success rounded-top border border-dark" style="width:100%; padding-left:8px;">
{{cat.cat_name}}
</div>
</div>
<div class="row">
<div class="bg-secondary border border-dark" style="width:100%; padding-left:16px;">
Forums_Go_Here
</div>
</div>
{% endfor %}
{% endblock content %}
I am trying to get a homepage where I would be able to list my categories and show the forums in those categories.
The template I have is running a for loop which is looping through all Categories.
In the shell i am able to get the forums with the: Category.objects.get(pk=2).get_forums() command. But this limits it to one category.
You can use related name for that, no need to use additional method:
{% block content %}
{% for cat in category %}
<div class="row">
<div class="bg-success rounded-top border border-dark" style="width:100%; padding-left:8px;">
{{cat.cat_name}}
</div>
</div>
{% for forum in cat.forums.all %}
<div class="row">
<div class="bg-secondary border border-dark" style="width:100%; padding-left:16px;">
{{forum.forum_name}}
</div>
</div>
{% endfor%}
{% endfor %}
{% endblock content %}
Also you have a mistake there:
context['category'] = Category.objects.all()
If you want to access it as category in template put it there with that key, not cat.
I'like to represent the list of news_list, the result should be like following style using 2 loops:
category1
-- info_record 1
-- info_record 2
category2
-- info_record 3
The problem is, inside loop {% for m in p_list.p.name %} always nothing happen, meanwhile outside loop {% for p in p_category %} could be retrieved properly.
html template file is shown as below,
{% block content %}
<div class = "container">
{% for p in p_category %}
<div class = "row" >
......... {{p}}
</br>
</div>
{% for m in p_list.p.name %}
<div calss ="row">
.. <a href = "/pubinfo/{{m.slug}}" > {{m.title}} - [ {{m.created}}] </a>
</div>
{% endfor %}
{% endfor %}
</div>
{% endblock %}
the view file is shown as below,
from django.shortcuts import render
from datetime import datetime
from .models import Category
from .models import PostInfo
def list_all(request):
post_categories = Category.objects.all()
post_lists ={}
for cate in post_categories:
post_lists[cate.name] = PostInfo.objects.all().filter(category = cate)
import pdb; pdb.set_trace()
return render(request, 'pub_post.html', {'p_category': post_lists.keys(), "p_list": post_lists})
model file is shown as below,
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=200,
db_index=True)
slug = models.SlugField(max_length=200,
db_index=True,
unique=True)
class Meta:
ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
class PostInfo(models.Model):
title = models.CharField(max_length=200,
db_index=True)
slug = models.SlugField(max_length=200,
db_index=True,
unique=True)
content = models.TextField(blank=True,
null=True)
category = models.ForeignKey(Category,
related_name='post_category')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User, related_name='created_by_user')
updated_by = models.ForeignKey(User, related_name='updated_by_user')
class Meta:
ordering = ('updated',)
# verbose_name = 'post'
# verbose_name_plural = 'posts'
def __str__(self):
return self.title
Appreciated if any one could give me your hand, thanks a lot again.
Thats because p_list is a dictionary.
Try this:
{% for key, value in p_list.items %}
{% if key == p %}
{% for m in value %}
<div calss ="row">
.. <a href = "/pubinfo/{{m.slug}}" > {{m.title}} - [ {{m.created}}] </a>
</div>
{% endfor %}
{% endif %}
{% endfor %}
.items convert the dictionary into a list of (key, value) pairs
Update, you can just replace the whole template with this and avoid the context variable p_category
{% block content %}
<div class = "container">
{% for p, values in p_list.items %}
<div class = "row" >
......... {{p}}
</br>
</div>
{% for m in values %}
<div calss ="row">
.. <a href = "/pubinfo/{{m.slug}}" > {{m.title}} - [ {{m.created}}] </a>
</div>
{% endfor %}
{% endfor %}
</div>
{% endblock %}
How should I create a for loop in my template so that I can show a ManyToMany relationship?
Given that:
in models.py I have
class Cycle(models.Model):
cycle_name = models.CharField(max_length=150)
cycle_description = models.CharField(max_length=250)
def __str__(self):
return self.cycle_name + " -- " + self.cycle_description
class Program(models.Model):
program_name = models.CharField(max_length=50)
program_description = models.CharField(max_length=250)
cycles = models.ManyToManyField(Cycle)
is_favourite = models.BooleanField(default="False")
def get_absolute_url(self):
return reverse('programs:program', kwargs={'pk': self.pk})
def __str__(self):
return self.program_name
in views.py
class AllProgramsView (generic.ListView):
template_name = 'programs/index.html'
context_object_name = 'programs_list'
def get_queryset(self):
return Program.objects.all()
class ProgramDetailView (generic.DetailView):
model = Program
template_name = 'programs/program.html'
in urls.py
#list of all programs
url(r'^$', views.AllProgramsView.as_view(), name='index'),
#single program page
url(r'^(?P<pk>[0-9]+)/$', views.ProgramDetailView.as_view(), name='program'),
In the single program page I need to list all the cycles that are contained in that specific program.
I've been trying so many different things but none seems to be right.
Here's my current take for the template, which however does not work:
program.html
<div class="bg-white">
<div class="container text-center text-muted">
<div class="row">
{% if cycle %}
{% for cycle in program.cycles.all() %}
<div class="col-sm-4 py-4">
<div class="card">
<p><h5>{{ cycle.cycle_name }}</h5></p>
<p class="card-text">{{ cycle.cycle_description }}</p>
Modify it
</div>
</div>
{% endfor %}
{% else %}
<div class="col-sm-12">
<p>No cycles found</p>
</div>
{% endif %}
</div>
</div>
Can someone help, please? Thanks.
I think that you get no context because the if statement is wrong.
Instead of
{% if cycle %}
it should be
{% if program.cycles %}