Get related cousin model in a template - python

I'm struggling finding docs or examples how to get data from a cousin related model.
So if the models look like this:
class Part(models.Model):
name = models.CharField(max_length=550)
class Quantity(models.Model):
quantity = models.DecimalField(max_digits=10, decimal_places=2)
part = models.ForeignKey('Part', related_name='quantity_part')
stockarea = models.ForeignKey('StockArea', related_name='quantity_stockarea')
class Stock(models.Model):
name = models.CharField(max_length=550)
class StockArea(models.Model):
area = models.CharField(max_length=550)
stock = models.ManyToManyField(Stock, related_name='stockarea_stock')
def __str__(self):
return self.area
And in the view I get the part like this:
def details(request, part_id):
part = get_object_or_404(Part, pk=part_id)
context = {
'part': part,
}
return render(request, 'part/details.html', context)
Finally template trying to display the data:
{% for a in part.quantity_part.all %}
{{ a.quantity }} pcs
Find part in area: {{ a.stockarea }}
in stock: {{ part.stockarea.stock.name }}
{% endfor %}
You see how I try to get the name of the stock. I can't figure out how to be able to get hold of the name of the stock. I have a path there from the part.
Part have a related_name to the Quantity model called quantity_park. And in the model Quantity I have a relation to model StockArea. And from there I have a relation to model Stock.
Guidance is much appreciated =)
Maybe I'm totally doing this backwards. Maybe I'm defining the models wrong to begin with. I'm used to MySQL, so this is very new to me.

The data model for this is better done as:
from django.db import models
class Unit(models.Model):
name = models.CharField(max_length=32)
description = models.TextField()
abbrev = models.CharField(max_length=7)
class Warehouse(models.Model):
name = models.CharField(max_length=100)
address = models.TextField()
class StockArea(models.Model):
warehouse = models.ForeignKey(Warehouse)
# Adjust type of these identifiers as necessary
aisle = models.PositiveIntegerField()
shelf = models.PositiveIntegerField()
class Part(models.Model):
name = models.CharField(max_length=550)
description = models.TextField()
class Stock(models.Model):
part = models.ForeignKey(Part, related_name='stock') # Adds a 'stock' attribute to 'Part'
quantity = models.PositiveIntegerField()
unit = models.ForeignKey(Unit)
location = models.ForeignKey(StockArea)
View code:
from django.views import generic
from .models import Part
class PartView(generic.DetailView):
# Pre-fetch related objects. This also illustrates the joins
queryset = Part.objects.prefetch_related(
'stock', 'stock__location', 'stock__location__warehouse'
)
template_name = 'yourapp/part/detail.html'
Template code yourapp/part/detail.html:
{% extends "base.html" %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-md-8 col-md-offset-2">
<h1 class="title">{{ part.name }}</h1>
<p>{{ part.description }}</p>
<h2>Stock information</h2>
<div class="container-fluid">
{% for stock in part.stock.all %}
<div class="row">
<div class="col-xs-3">
Aisle {{ stock.location.aisle }}, shelf {{ stock.location.shelf }}
</div>
<div class="col-xs-3 label">
Warehouse:
</div>
<div class="col-xs-6">
{{ stock.location.warehouse.name }}
<address>
{{ stock.location.warehouse.address }}
</address>
</div>
</div>
<div class="row">
<div class="col-xs-3 label">
Available:
</div>
<div class="col-xs-8 numeric">
{{ stock.quantity }}
</div>
<div class="col-xs-1 unit">
{{ stock.unit.abbrev }} <sup><i class="fa fa-icon" title="{{ stock.unit.name }}"></i></sup>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock content %}
Edit:
Fixed model relation for stock/part.
Adjusted data model conforming specs in comments
Added view code to illustrate join and point to prefetch_related.
Adjusted template to match changes

Related

ListView in Django

I am using Class Based views and want to display data on a webpage using ListView. Am using for loop to display many objects data. In my models, the items have a category field which is ForeignKey where the category is either Bags, Tshirts or Shoes. I want to display items whose Category is Shoes only. I have tried using the if condition which isnt working with the ForeignKey field. How do I filter the Category field to display Bags only?
models.py
from django.db import models
# Create your models here.
class Category(models.Model):
title = models.CharField(max_length=30)
createdtime = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "Categories"
class Product(models.Model):
mainimage = models.ImageField(upload_to='product')
name = models.CharField(max_length=264)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category')
previewtext = models.TextField(max_length=200, verbose_name='Preview Text')
detailstext = models.TextField(max_length=1000, verbose_name='Description')
price = models.FloatField()
oldprice = models.FloatField(default=0.00)
createddate = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
ordering = ['-createddate',]
views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from shopapp.models import Product
# Create your views here.
class Home(ListView):
model = Product
template_name = 'shopapp/home.html'
html file
<div class="container my-5">
<h2 class="my-5">Handbags</h2>
<div class="row">
{% for product in object_list %}
{% if product.category == 'Bags' %}
<div class="col-md-6 col-sm-12 col-lg-3">
<figure class="card card-product">
<div class="img-wrap">
<img src="/media/{{ product.mainimage }}" style="width:100%; height:300px;">
</div>
<figcaption class="info-wrap">
<h6 class="title">{{ product.name }}</h6>
<div class="action-wrap">
<div class="price-wrap h5">
<span class="price-new">${{ product.price|floatformat:2 }}</span>
<span class="price-old"><strike>${{ product.oldprice|floatformat:2 }}</strike></span>
</div>
</div>
</figcaption>
</figure>
</div>
{% endif %}
{% endfor %}
</div>
</div>
In your code use product.category.title like so:
...
{% if product.category.title == 'Bags' %}
...
You are comparing a Category object with the string Bags.
//edit
I also recommend filtering the data in the view, if you only need that data in the view. There is no need to fetch all the products from your database and send them to the view, just to render a portion of it.

restrict content on django views

I am trying to do this all vip user paid that contains type 2 allow to see the full information , but however it does as expect, but with a minor issue , it hide the lesson to the end-user if this doesnt belong to x user logged. I want to keep lesson displayed to the end-user, but however if the user tries to click to the lesson then display upgrade account instead of hidding content. how can I achieve this?
model
class Lesson(models.Model):
content_title = models.CharField(max_length=120)
content_text = models.CharField(max_length=200)
thumbnail = models.ImageField(upload_to='xxx/xxx/xxx/xxx/xxx')
link = models.CharField(max_length=200, null=True)
allowed_memberships = models.ManyToManyField(Membership)
def __str__(self):
return self.content_title
view
def get_context_data(self, **kwargs):
context = super(bootCamp, self).get_context_data(**kwargs)
lesson = Lesson.objects.first()
user_membership = UserMembership.objects.filter(user=self.request.user).first()
user_membership_type = user_membership.membership.membership_type
lesson_allowed_mem_types = lesson.allowed_memberships.all()
context['lessons_allowed_mem_types'] = lesson_allowed_mem_types
context['lessons'] = None
if lesson_allowed_mem_types.filter(membership_type=user_membership_type).exists():
if Lesson.objects.filter(allowed_memberships=1):
context['lessons'] = Lesson.objects.filter(allowed_memberships=1).values()
elif Lesson.objects.filter(allowed_memberships=2):
context['lessons'] = Lesson.objects.filter(allowed_memberships=2).values()
else:
pass
return context
template
{% if lessons is not None %}
{% for lessson in lessons %}
<div class="col-md-3">
<a href="/{{ lessson.link }}">
<div class="item">
<div class="content-overlay"></div>
<img src="/{{ lessson.thumbnail }}" />
<div class="content-details fadeIn-bottom">
<h3 class="content-title">{{ lessson.content_title }}</h3>
<p class="content-text">{{ lessson.content_text }}</p>
</div>
</div>
</a>
</div>
{% endfor %}
{% else %}
<p>upgrade</p>
{% endif %}
I would recommend to check the count of the retrieved lessons if it is less than 1 then redirect to the upgrade view/template.

Django - display the right variable

My Goal:
If the user has score > 1 display only the jobs that have the correlated category. So, if category.1 (name of the quiz) is DataScience, shows only the jobs that are about Data Science.
What my result is:
If the score > 1 it displays all the job offers present on the database. (as in picture)
What am I doing wrong? Any suggestions?
quiz/models.py
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
class Questions(models.Model):
CAT_CHOICES = (
('datascience', 'DataScience'),
('productowner', 'ProductOwner'),
('businessanalyst', 'BusinessAnalyst'),
#('sports','Sports'),
#('movies','Movies'),
#('maths','Maths'),
#('generalknowledge','GeneralKnowledge'),
)
question = models.CharField(max_length = 250)
optiona = models.CharField(max_length = 100)
optionb = models.CharField(max_length = 100)
optionc = models.CharField(max_length = 100)
optiond = models.CharField(max_length = 100)
answer = models.CharField(max_length = 100)
catagory = models.CharField(max_length=20, choices = CAT_CHOICES)
student = models.ManyToManyField(User)
class Meta:
ordering = ('-catagory',)
def __str__(self):
return self.question
jobs/models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class post_job(models.Model):
posizione= models.CharField(max_length=20)
descrizione= models.TextField(max_length=60)
requisiti= models.TextField(max_length=60)
nome_azienda= models.CharField(max_length=20, default=' inserisci nome')
email_referente= models.CharField(max_length=20, default='inserisci email')
core/views.py
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.list import ListView
from .decorators import allowed_user
# Create your views here.
from quiz.models import Questions
from jobs.models import post_job
from functools import wraps
#allowed_user(allowed_roles=['Admin','Students'])
def userProfileView(request, username):
user= get_object_or_404(User, username=username)
jobs = post_job.objects.all()
categories = Questions.CAT_CHOICES
scores = []
for category in categories:
score = Questions.objects.filter(catagory=category[0], student= user).count()
scores.append(score)
context = {
'user' : user, 'categories_scores' : zip( categories,scores),
'jobs': jobs
}
return render(request, 'core/user_profile.html' , context)
core/user_profile.html
{% extends 'base.html'%}
{% block content %}
<br>
<div class="card-header">
<h3> {% if request.user == user %} Il tuo {% endif %} Profilo Utente </h3>
<br>
<h1> Ciao Studente: #{{ user }}</h1>
</div>
<br>
<br>
{% for category,score in categories_scores %}
<div class="card">
<div class="card-header">
{{ category.1 }} Score
</div>
<div class="card-body">
<h5 class="card-title">CONGRATS!</h5>
<p class="card-text"> Here your SCORE: </p>
{{ score }}
{% if score > 1 %}
{% if request.user == user %}
<br>
<br>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: 99%" aria-valuenow="99" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<p class="card-text"> Congratulations! Now you can apply to:</p>
<br>
{% for job in jobs %}
<div id="accordion">
<div class="card">
<div class="card-header" id="headingOne">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
{{job.posizione}} <strong> {{job.nome_azienda}} </strong>
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
<ul>
<li> {{job.descrizione}} </li>
<li> {{job.email_referente}} </li>
</ul>
</div>
</div>
</div>
{% endfor %}
{% endif %}
{% else %}
<br>
<br>
<div class="progress">
<div class="progress-bar bg-warning" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<p class="card-text"> Still not meet the requirements to apply, keep going! </p>
{% endif %}
</div>
</div>
<br>
{% endfor %}
{% endblock content %}
On the line in the template,
{% for job in jobs %}
You are expecting this to be just the jobs in which the user has scored > 1, but the code never filtered on it, so it's getting all jobs.
One solution could be to add a field on the post_job Model for Question.category, so that you can filter them down.
Like you said in the comments, there's no connection to between the job and the questions, so that needs to be created.

Django Template Filter With Respect to Boolean Variable

My Html
{% for category in categories %}
<div class="row">
<h3 style="padding-left: 15px; padding-bottom: 15px">{% filter upper %}{{ category.name }}{% endfilter %}</h3>
</div>
<div class="row">
{% with products=category.product.all|is_available:True %}
{% for product in products|slice:":4" %}
<div class="product-width col-xl-3 col-lg-3 col-md-3 col-sm-6 col-12 mb-30">
<div class="product-wrapper">
<div class="product-img">
<a href="{% url 'shop:product' category.name product.id %}">
<img alt="" src="{{product.image.all.0.image.url }}">
</a>
<div class="product-action">
<a class="action-wishlist" href="#" title="Wishlist">
<i class="ion-android-favorite-outline"></i>
</a>
<a class="action-cart" href="#" title="Add To Cart">
<i class="ion-android-add"></i>
</a>
</div>
</div>
<div class="product-content text-left">
<div class="product-title">
<h4>
{{ product.name|title }}
</h4>
</div>
<div class="product-price-wrapper">
<span>{{product.price}} TL</span>
</div>
</div>
</div>
</div>
{% endfor %}
{% endwith %}
</div>
<div class="row justify-content-end">
Daha Fazla...
</div>
{% endfor %}
My Model
Each product has a many-to-many relation with categories and products also have an is_available variable.
class ProductCategories(models.Model):
name = models.CharField(max_length = 60)
image = models.ImageField(upload_to = 'ProductCategories')
publish_date = models.DateTimeField(auto_now=False, auto_now_add=True)
is_available = models.BooleanField()
class Product(models.Model):
category = models.ManyToManyField(ProductCategories, related_name="product")
name = models.CharField(max_length = 60)
price = models.DecimalField(max_digits=65, decimal_places=2)
description = models.TextField()
publish_date = models.DateTimeField(auto_now=False, auto_now_add=True)
stock_number = models.IntegerField()
is_available = models.BooleanField()
My View
categories = ProductCategories.objects.all()
return render(request, 'shop/shopping.html', {'categories' : categories})
I am listing 4 products under each category but I would like to filter products that are available.
Should I filter products within view class and pass to template filtered product object separate Queryset or should I apply all filters within the template?
If I should filter them within the template as I tried above, is there any way to filter product objects according to their availability?
Thanks,
class ProductManager(models.Manager):
def is_available(self):
return self.get_queryset().filter(is_available=True)
class Product(models.Model):
--------
objects = ProductManager()
views.py
product = Product.objects.is_available()
return render(request, 'shop/shopping.html', {'products' : product})
templates
{% for product in products %}
{{ product.name }}
{% for item in product.category.all %}
{{ item.name }}
{% endfor %}{% endfor %}
Create a folder called "templatetags" at the same level as models.py and views.py in your application folder
Create a new file with the desired name in this folder. For example : 'app_tags.py'
Create a new file named __ init __.py in this folder
Open app_tags.py and write this code sample for create custom template filter:
from ..models import ProductCategories
from django import template
register = template.Library()
#register.filter
def is_available(value, arg):
products = value.filter(is_available = arg)
return products
And use like this in your Html:
{% load app_tags %}
...
...
...
{% with products=category.product.all|is_available:True %}
...
...
Please try this solution. I hope this helps to you.

Django get the foreign key object value

I wrote a model and saved some data, but now I don't know how to query the object along with the foreign key model.
Here is my models.py:
class Movie(models.Model):
link = models.URLField()
title = models.CharField(max_length=255, null=True)
title_en = models.CharField(max_length=255, null=True)
class MovieImage(models.Model):
movieimage = models.ForeignKey(Movie,null=True,blank=True)
img_link = models.URLField(max_length=255, null=True)
view.py:
def index(request):
obj = Movie.objects.all()
contacts = get_paginator(request, obj, 10)
return render_to_response("movie/index.html",
{'title': title ,'obj':obj,'contacts':contacts},
context_instance=RequestContext(request))
And movie/index.html:
{% for o in obj %}
<div class="col-md-12 item">
<p><h3>{{ o.title }}</h3></p>
<div class="pic">
{{ o.img_link }} <!--I want to show the img_link but don't know how to do this -->
</div>
</div>
{% endfor %}
I know I can use o.title ,o.entitle to get the value. But I don't know how to get the value in foreign key model from there
First - Some naming conventions - obj is a terribly general name that doesn't mean anything. It's probably a good idea to use something like movies. Also, if the model is named MovieImage, why have a field called img_link? That's kinda repetitive, don't you think? This way would be better:
#models.py
class MovieImage(models.Model):
movie = models.ForeignKey(Movie,null=True,blank=True)
src = models.URLField(max_length=255, null=True)
Then you could do:
#views.py
def index(request):
movies = Movie.objects.all() # movies instead of obj
contacts = get_paginator(request, movies, 10)
return render(request, "movie/index.html",
{'title': title ,'movies':movies,'contacts':contacts})
finally, for the actual answer - the default name for the related objects are foo_set (in your case, movieimage_set) which you can iterate over like so:
# html
{% for movie in movies %}
<div class="col-md-12 item">
<p><h3>{{ movie.title }}</h3></p>
<div class="pic">
{% for image in movie.movieimage_set.all %}
<img src="{{ image.src }}"> <!-- I am assuming you actually want to show the image, not just the link -->
{% endfor %}
</div>
</div>
{% endfor %}
p.s.
You might've noticed, I replaced render_to_response in the views with render. Here's why
As I told you on comments, you can have more than a MovieImage for each Movie, soy you need to iterate over them.
{% for o in obj %}
<div class="col-md-12 item">
<p><h3>{{ o.title }}</h3></p>
<div class="pic">
{% for image in o.movieimage_set.all %}
{{image.img_link}}
{% empty %}
<p>This obj doesn't have any image</p>
{% endfor %}
</div>
</div>
{% endfor %}

Categories

Resources