Django menu & childmenu from models - python

I'm trying to a menu system for my sport site project where the sports are grouped together. For example the main category would be "ballsports" and under that (the child menu) people would select football, baseball or whatever else. I've got that all setup and functioning but I can't workout how to call the child menus into the templates.
Models:
class Sport(models.Model):
name = models.CharField(max_length=100, db_index=True)
sport_slug = models.SlugField(max_length=100, db_index=True)
category = models.ForeignKey('Sport_Category', on_delete=models.CASCADE,)
class Sport_Category(models.Model):
name = models.CharField(max_length=100, db_index=True)
category_slug = models.SlugField(max_length=100, db_index=True)
Views:
class IndexView(generic.ListView):
template_name="sports/index.html"
context_object_name='all_sport_category'
def get_queryset(self):
return Sport_Category.objects.all()
def list_of_sports_in_category(self):
sport_cat = self.category.name
return sport_cat
class SportListView(generic.ListView):
template_name="sports/sport-home.html"
context_object_name='sport_list'
def get_queryset(self):
return Sport.objects.all()
Template:
{% for sport_category in all_sport_category %}
<li>{{ sport_category.name }} </li> *(Working)*
{% for sports in list_of_sports_in_category %}
hi
{% endfor %}
{% endfor %}

list_of_sports_in_category method seems to return the category name, rather than the list of sports. try replacing the second for-loop in your template with {% for sport in sport_list %}.

Related

Adding Context to Class Based View Django Project

I have a problem with showing a queryset of a specific model in my Gym project. I have tried many different query's but none is working
the models:
class Workout(models.Model):
name = models.CharField(max_length = 30,blank=True, null=True)
class Exercise(models.Model):
workout = models.ForeignKey(Workout, on_delete=models.CASCADE, related_name='exercises',blank=True, null=True)
name = models.CharField(max_length = 30, blank=True, null=True)
class Breakdown(models.Model):
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE, related_name='excercise',blank=True, null=True)
repetitions = models.IntegerField()
I am trying to showing the repetitions in the Breakdown model which has a ForeignKey relation with Exercise which has a ForeignKey relation with Workout
views.py
class home(ListView):
model = Workout
template_name = 'my_gym/home.html'
context_object_name = 'workouts'
class workout_details(ListView):
model = Exercise
template_name = 'my_gym/start_workout.html'
context_object_name = 'exercises'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['breakdown'] = Exercise.objects.filter(breakdown=self.breakdown)
return context
urls.py
urlpatterns = [
path('', home.as_view(), name='home'),
path('workout/<int:pk>/', workout_details.as_view(), name='workout'),
]
template:
{% for e in exercises %}
{{ e.name }}
{{ breakdown.repetitions }}
{% endfor %}
My question what is my mistake here that is either getting me an error or not showing the required data set. my objective is the choose from the home page a Workout from list and next page to be the list of exercises with the repitions related to it.
get_context_data() is a method calculated for view, not a loop to use inside a template or something similar. You have set nice relations, use them properly.
Firstfully, change related_name here to something that will not be confusing:
class Breakdown(models.Model):
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE, related_name='breakdowns', blank=True, null=True)
With that done, delete whole get_context_data() and change template to:
{% for e in exercises %}
{{ e.name }}
{% for b in e.breakdowns.all %}
{{ b.repetitions }}
{% endfor %}
{% endfor %}

Filtering through relationship in views or template

I have one simple model called Product
class Product(models.Model):
title = models.CharField(max_length=150)
def __str__(self):
return self.title
And one other model called ExternalProduct
class ExternalProduct(models.Model):
title = models.CharField(max_length=100)
external_id = models.CharField(max_length=25)
internal_product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
blank=True,
related_name='external_products',
)
price = models.IntegerField()
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, blank=True)
image_url = models.CharField(max_length=255)
product_url = models.CharField(max_length=255)
store = models.CharField(max_length=50)
active = models.BooleanField(default=True)
class Meta:
ordering = ['price']
def __str__(self):
return self.title
On the detailed view of the Product, I want to display the price of all ExternalProduct related to the Product. It works all fine with this view
# products/views.py
class ProductDetailView(DetailView):
model = Product
context_object_name = 'product'
template_name = 'products/product_detail.html'
and this template
# product_detail.html
{% extends '_base.html' %}
{% block title %}{{ product.title }}{% endblock title %}
{% block content %}
<div class="book-detail">
<h2>{{ product.get_active_external_products }}</h2>
</div>
<div>
<ul>
{% for ep in product.external_products.all %}
<li>{{ ep.price }}</li>
{% endfor %}
</ul>
</div>
{% endblock content %}
The problem is that I just want to display the price of ExternalProduct which has active=True
Been trying to solve it with a custom method in products views.py
class ProductDetailView(DetailView):
model = Product
context_object_name = 'product'
template_name = 'products/product_detail.html'
def get_active_external_products(self):
return self.external_products.objects.filter(active=True)
And a modified for loop inside product_detail.html
{% for ep in product.get_active_external_products %}
<li>{{ ep.price }}</li>
{% endfor %}
But unfortunately without any success. The site does not crash, just doesn't show anything other than the rest of the html file.
Any advice?
You can use prefetch_related with Prefetch to filter only active external products. For this you need to override get_queryset() method in your view:
from django.db.models import Prefetch
class ProductDetailView(DetailView):
model = Product
context_object_name = 'product'
template_name = 'products/product_detail.html'
def get_queryset(self):
return Product.objects.prefetch_related(Prefetch("external_products", queryset=ExternalProduct.objects.filter(active=True), to_attr="active_external_products"))
Note to_attr="active_external_products" part. It tells that active external products will be available as active_external_products attribute. So in template you can get them like this:
{% for ep in product.active_external_products %}
<li>{{ ep.price }}</li>
{% endfor %}
Or you can just override get_context_data() to insert external products to the context directly:
class ProductDetailView(DetailView):
model = Product
context_object_name = 'product'
template_name = 'products/product_detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(****kwargs)
context["active_external_products"] = self.object.external_products.filter(active=True)
return context
In this case in template you can use active_external_products variable name directly:
{% for ep in active_external_products %}
<li>{{ ep.price }}</li>
{% endfor %}

How to access child class object that inherits parent class?

I have parent class and child class, that inherits parent class. And that is okay, I can iterate with for loop. Now I want to access child class (example: 'product_type' So basically, I'm confused how we inherits stuff from child class inside the same loop...
views.py
from django.views import generic
from . models import Category
from django.shortcuts import render
class CategoryListView(generic.ListView):
model = Category
template_name = 'category_list.html'
models.py
from django.db import models
import uuid
class Category(models.Model):
name = models.CharField(max_length=100, help_text='Category name')
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Categories'
class Product(models.Model):
product_name = models.CharField(max_length=255, help_text='Product name')
# product_spec = models.TextField(max_length=5000, help_text='Product specs')
product_type = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.product_name
category_list.html
{% extends 'base.html' %}
{% block body %}
{% for page in category_list %}
<li>{{ page.name }}</li>
<li>{{ page.product_name }} # <--------------- Now this is the point of
#my problem, I want to get
#product name from child
#class
#this returns empty <li>
{% endfor %}
{% endblock %}
you can to this
{% extends 'base.html' %}
{% block body %}
{% for page in category_list %}
<li>{{ page.name }}</li>
<li>{{ page.product_set.first.product_name }}
product name from child class, this returns empty <li>
{% endfor %}
{% endblock %}
First off change your product_type name to just category its way easier to understand and add an attribute related_name to it like this:
class Product(models.Model):
name = models.CharField(max_length=255, help_text='Product name')
category = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True, related_name='products')
then in your template
{% for category in category_list %}
{{ category.name }}
{% for product in category.products.all %}
{{ product.name}}
... other product data
{% endfor %}
{% endfior %}
product_typein Product is a ForaignKey which means their will be multiple products having same Category so their exist two solutions
make product_type in Product one to one key, with this you shuld get single name by {{ page.product.product_name }}
print list of all products of the category, you can do this by iterating page.product_set as it is a list (iterable) with for loop.

Django TypeError objects is not iterable in Templates

I have two models one is club details and the other is player structure. so my plan is to based on the club iteration which has values like'test', 'odi', 'listA' i need to represent its respective player structure in my Django template.
models.py
class Clubstate(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class PlayerStructure(models.Model):
clubstate = models.ForeignKey('Clubstate', on_delete=models.CASCADE, related_name='clubstate')
country = models.ForeignKey('TeamStructure', on_delete=models.CASCADE, null=True, related_name='identifier1')
firstname = models.CharField(max_length=255)
lastname = models.CharField(max_length=255)
imageUri = models.ImageField(upload_to='images/', verbose_name='image')
JerseyNumber = models.IntegerField()
def __str__(self):
return self.firstname + self.lastname
In views.py I'm using DetailView to represent the data.
class PlayerStatistics(DetailView):
context_object_name = 'Clubstate_details'
model = models.Clubstate
template_name = 'CricketDetails/playerstatistics_details.html'
Template html
<div class="jumbotron">
<div class="container">
<div class="row">
{% for club in Clubstate_details %}
<h1>{{club.name</h1>
{% endfor %}
</div>
</div>
</div>
My thought, logic is like
{% for club in clubs %}
{{club.name}}
{{club.player_structure.firstname}}
{{club.player_structure.lastname}}
{% endfor%}
So that for indivdual club i get its respective player structure.
I get TypeError: 'Clubstate' object is not iterable error.
Hope that makes sense...
Detail view won't give a list of items, instead it gives a single view only so change the DetailView to ListView and iterate through the output
class PlayerStatistics(ListView):
context_object_name = 'Clubstate_details'
model = models.Clubstate
template_name = 'CricketDetails/playerstatistics_details.html'
if you want detail view can get it by
{{ Clubstate_details.name }}
with DetailView
FK instance can be accessed by
{% for obj in Clubstate_details.playerstructure_set.all %}
{{ obj.firstname }}
{% endfor %}

Trouble getting related fields in ForeignKeys to show in Template

I'm working in Django 2.2 trying to build a view for a database that compiles everything for a specific company (locations of all of their stores and notes on the companies) into a single view. I've tried methods in several different answers, but still cannot seem to get data from related foreign keys to show in the template.
models.py
class Company(models.Model):
name = models.CharField(max_length=30, primary_key=True)
official_name = models.CharField(max_length=50)
corporate_address1 = models.CharField(max_length=50)
corporate_address2 = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
slug = models.SlugField(max_length=30, unique=True)
def __str__(self):
return self.name
class Stores(models.Model):
store_name = models.CharField(max_length=30, primary_key=True)
owner = models.ForeignKey('Company', on_delete=models.CASCADE)
store_address1 = models.CharField(max_length=50)
store_address2 = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
type = models.CharField(max_length=30,choices=store_types)
slug = models.SlugField(max_length=30, unique=True)
def get_absolute_url(self):
return reverse("store-detail", kwargs={"slug": self.slug})
class notes(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
posted = models.DateTimeField(db_index=True, auto_now_add=True)
category = models.ForeignKey('Company', on_delete=models.CASCADE)
active = models.BooleanField(default=True)
def get_absolute_url(self):
return reverse("article-detail", kwargs={"id": self.id})
class Country(models.Model):
country = models.CharField(max_length=30,choices=countries,primary_key=True)
class Meta:
ordering = ["-country"]
db_table = 'country'
def __str__(self):
return self.country
views.py
class CompanyOverView(LoginRequiredMixin, DetailView):
model = Company
template_name = "company-overview.html"
slug_url_kwarg = 'slug'
query_pk_and_slug = True
pk_url_kwarg = "company.name"
template
<div align="center">
<p>{{ object.name }}<br>({{ object.official_name }})</p>
<p>{{ object.corporate_address1 }}<br>{{ object.corporate_address2 }}<br>
{{ object.city }}<br>{{ object.state_province }}<br>
{{ object.country }}</p>
</div>
<p>List of Stores</p>
<p>
{% for instance in object_list %}
{{ instance.company.stores.store_name }}
{{ instance.company.stores.store_address1 }}
{{ instance.company.stores.store_address2 }}
{{ instance.company.stores.city }}
{{ instance.company.stores.state_province }}
{{ instance.company.stores.country }}
{% endfor %}
</p>
<p>Notes</p>
<p>
{% for instance in object_list %}
{{ instance.company.notes.title }}
{{ instance.company.notes.posted }}
{% endfor %}
</p>
With the above code, the only thing that appears when you enter in the company's name is everything at the top (e.g."object.name" appears on the page as "Acme Corporation"). Nothing in the for loop appears on the web page.
Looking at the documentation, object_list is the default name for context unless specified. I have tried different combinations such as "for store_name in company.store_set.all" and other combinations I found in other posts, but none have worked. I've combed the documentation for everything related to foreign keys, but can't find a solution that works.
Thanks in advance if you can help.
No. object_list is the default context name in a ListView. But you have a DetailView, and you already know what the default context name is for those because you're already using it: object. You just need to iterate over the reverse relation from there:
{% for store in object.stores_set.all %}
{{ store.store_name }}
{{ store.store_address1 }}
...
{% endfor %}

Categories

Resources