Django models: you need to display the menu and submenus - django

Can you please help. That's the question. I have a menu, the name of the menu is 'catr' and there is a submenu 'subcat' , I want to make the entire menu list output, and if the menu id matches the menu, then a subcategory is output, but I don't understand how to implement it.Help please.Sorry if I didn't explain it clearly, I hope you will understand, thank you in advance
Here's what I tried to do
enter image description here
enter image description here

From what I can understand you can do this using functions in your models like this...
class Category(models.Model):
name = models.CharField(max_length=100 db_index=True)
slug= models.SlugField(max_length=255, unique=True, db_index=True, verbose_name = 'URL')
def ___str__(self):
return self.name
def get_absolute_url(self):
return reverse('category' kwargs={'cat_slug':self.slug})
def get_sub_category(self):
return Subcategory.objects.filter(parent_category=self)
class Meta:
verbose_name = 'Kатегоpии'
verbose_name_plural = 'Kaтегоpии'
ordering = ['id']
and in your templates do this...
{% for item in catr %}
<li>
{{item.name}}
{% if item.get_sub_category %}
<ul>
{% for child in item.get_sub_category %}
<li>{{ child.sub }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}

Related

How to delete a record only if the user posted is the logged in user

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 %}

Rendering ForeignKey objects in template with Django

I'm having trouble rendering related objects in a template. I have a Page model, that has a ForeignKey relationship to itself to define parent-child relationships.
class Page(BaseModel):
title = models.CharField(
max_length=280,
blank=False,
null=False,
)
description = models.CharField(
max_length=280,
blank=False,
null=False,
)
slug = models.SlugField(
blank=False,
null=False,
)
is_home = models.BooleanField(
default=False,
)
is_parent = models.BooleanField(
default=False,
)
parent = models.ForeignKey(
'self',
on_delete=models.PROTECT,
default='Home',
blank=True,
null=True,
related_name='children',
)
content = RichTextField(
blank=False,
null=False,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('page_detail', args=[str(self.slug)])
My views.py filters out non-parent pages:
class PageListView(ListView):
queryset = Page.objects.filter(is_parent=True, is_home=False)
template_name = 'pages/page_list.html'
context_object_name = 'page'
But when it comes to rendering 'child' objects in my template, I'm stuck. I've figured that I need a loop within a loop (first for parent pages, second for child pages per parent page), but can't get the second loop to work. Here was my latest attempt, which got me a "'Page' object is not iterable" error.
{% extends '_base.html' %}
{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% for children in page %}
<p>{{ page.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
You can iterate over the manager constructed by the related_name:
{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% for child in page.children.all %}
<p>{{ child.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
You can boost efficiency with a .prefetch_related(…) [Django-doc] clause:
class PageListView(ListView):
queryset = Page.objects.filter(
is_parent=True, is_home=False
).prefetch_related('children')
template_name = 'pages/page_list.html'
context_object_name = 'page'
I would furthermore advise not to create an extra field is_parent, since this is a form of data duplication. It turns out that keeping fields in sync, even on the same database, might be harder than what it appears to be at first sight. You can check if the object is a parent with:
class PageListView(ListView):
queryset = Page.objects.filter(
children__isnull=False, is_home=False
).distinct().prefetch_related('children')
template_name = 'pages/page_list.html'
context_object_name = 'page'

Not able to display in Template the foreign key using ListView

I'm trying to display a photographic session with all of it photos, so I have the session name in one model and I have the pictures in
another model linked by a foreign key. I'm not able to display it in
the HTML I'm not sure if I'm using the ListView get_context_data
correctly and I'm certainly sure the the html code is not correct but
I have not found how to do it.
views.py
class SessionPictures(generic.ListView):
model = PostSession
template_name = 'photoadmin/gallery.html'
def get_context_data(self, **kwargs):
context = super(SessionPictures, self).get_context_data(**kwargs)
context['picture'] = Images.objects.all()
return context
models.py
class PostSession(models.Model):
session_name = models.CharField(max_length=25)
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.session_name)
class Images(models.Model):
name = models.ForeignKey(
PostSession, related_name='images', on_delete=models.CASCADE, null=True, blank=True)
picture = models.ImageField(upload_to='pictures')
html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h2>Images</h2>
<ul>
{% for session in object_list %}
<li>{{ session.session_name }}</li>
<ul>
<li>{{session.picture_set.all.url}}</li>
</ul>
{% endfor %}
</ul>
{% endblock %}
I'm expecting this:
Woods
picture1.url
picture2.url
picture3.url
Beach
Picture4.url
picture5.rul
As you already defined related_name="images" in Images model, so, session.images_set attribute won't work with PostSession.
class Images(models.Model):
name = models.ForeignKey(
PostSession,related_name='images', on_delete=models.CASCADE, null=True, blank=True)
Instead, use session.image.all in template(FYI: it returns a queryset, so you need to iterate through it to get the image object):
{% for session in object_list %}
<li>{{ session.session_name }}</li>
<ul>
{% for i in session.images.all %}
<li> i.picture.url </li>
{% endfor %}
</ul>
{% endfor %}
More information on reverse relation can be found in documentation.

Nested querysets in Django

Having a bit of trouble getting my Django app to display how I'd like it. My model looks like this:
class City (models.Model):
city_name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.city_name
class Portfolio(models.Model):
portfolio_name = models.CharField(max_length=20, unique=True)
city = models.ForeignKey(City, db_constraint=False, on_delete=models.CASCADE)
def __str__(self):
return self.portfolio_name
class Property (models.Model):
portfolio = models.ForeignKey(Portfolio, db_constraint=False, on_delete=models.CASCADE)
prop_name = models.CharField(max_length=250, unique=True)
def __str__(self):
return self.prop_name
I want my template to display each City, and under each City have its Portfolios, and under each portfolio have its Properties. I'm a bit new to Django, coming from AngularJS where I could do it like this to throw filters in my loops(obviously doesn't work in Django, at least how I'm doing it):
<ul>
{% for city in all_cities %}
<li>
{{ city.city_name }}
<ul>
{% for portfolio in all_portfolios| portfolio.city = city %}
<li>
{{ portfolio.portfolio_name }}
<ul>
{% for property in portfolio.all_properties| property.portfolio = portfolio%}
<li>
{{ property.prop_name }}
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Any ideas? There is probably a simple solution that I just can't verbalize yet. The only thing I've found to do it like this is to create a custom queryset for each city, then for each portfolio, but there has to be a better way to do this.
Ignoring the fact that it is not database efficient to do this, the easiest way is to just make sure you are accessing the reversed Foreign Key relationships correctly.
Do something like this:
{% for city in all_cities %}
...blah blah blah
{% for portfolio in city.portfolio_set.all %}
... Blah blah
{% for property in portfolio.property_set.all %}
... More blah
And you should be good to go

Sort subchild into child into parent django

This is mainly working (thanks to a lot of help on a previous question. Sort children into parent in django template
Now I would like to sort sub-children objects into the children objects and then sort the children into their parent. Specifically, I want to sort schools into cities into their respective state. Then, I want the schools to display into the right city in its correct state. What I am looking for would like like this:
State
--- City
-----School
-----School
-----School
--- City
-----School
-----School
-----School
--- City
-----School
-----School
-----School
Right now, I have the cities sorting into the state. However, I cannot figure out to make the schools sort into the city. I am reading up on filters in the documentation. I think the answer lies there. However, I when try to filter the schools into the city, no objects come back.
Is there a way to retrieve the 'school_list' as a child of 'city_list' while still keeping the 'city_list a child of the states ? I would love to learn how.
Edit: Added the School model. Sorting the schools by name inside a city would be ideal.
Any and all help would be appreciated.
Edit: dkarchmer's solution worked perfectly. Thanks again. Hopefully, this will be useful to someone else in the future.
models.py
class State(models.Model):
state_name = models.CharField(max_length=20, default='')
state_slug = models.SlugField()
state_image = models.ForeignKey(Image, null=True)
state_summary = models.TextField(null=True)
def __str__(self):
return self.state_slug
class City(models.Model):
city_name = models.CharField(max_length=55, default='')
city_slug = models.SlugField()
state_image = models.ForeignKey(Image, null=True)
school_image = models.ForeignKey(Image, null=True, related_name='+')
state = models.ForeignKey(State, null=True)
def __str__(self):
return self.city_slug
def def sorted_schools(self):
return self.school_set.all().order_by('school_name')
class School(models.Model):
school_name = models.CharField(max_length=55, default='')
school_slug = models.SlugField()
city = models.ForeignKey(City, null=True)
def __str__(self):
return self.school_slug
views.py
class CityInStateView(ListView):
model = City
template = 'template.html'
slug_field = 'state_slug'
context_object_name = 'city_in_state_list'
def get_context_data(self, **kwargs):
context = super(CityInStateView, self).get_context_data(**kwargs)
context['state'] = self.object
context['city_list'] = self.object.city_set.all().order_by('city_name')
return context
urls.py
urlpatterns = [
url(r'^$', SchoolIndexView.as_view(), name='school_index'),
url(r'^(?P<state_slug>[\w-]+)/$', CityInStateView.as_view(), name='state_index'),
]
template.html
{% block main_content %}
<div class="row body">
<div class="main_content">
<div class="row">
<h1>{{ state.state_name }}</h1>
{% for city in city_list %}
<h2>{{ city.city_name }}</h2>
{% for school in city.sorted_schools %}
<h3>{{ school.school_name }} </h3>
{% endfor %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
This has been kicking my butt for a week. Please explain it to me like I a m five. I appreciate all of your help in advance.
The easiest is to just add a method to the City model to return Schools:
class City(models.Model):
...
def sorted_schools(self):
return self.school_set.all().order_by('school_name')
And then use that directly from the template:
<div class="row body">
<div class="main_content">
<div class="row">
<h1>{{ state.state_name }}</h1>
{% for city in city_list %}
<h2>{{ city.city_name }}</h2>
{% for school in city.sorted_schools %}
<h3>{{ school.school_name }} </h3>
{% endfor
{% endfor %}
</div>
</div>
</div>
If you don't want to add that method to the Model, the second alternative is to use a templatetag to basically do the same.