how to make specific model field dynamic from another model - django

I have two models Damaged and Product.In the Product model the quantity of the product depends upon the value of damaged_quantity which is stored in another table.For example if the damaged_quantity is in damaged table then the value of quantity in product should be quantity-damaged_quantity if the damaged.product_id == product.id .I tried like this but it is not working
models.py
class Damaged(models.Model):
product = models.ForeignKey('Product', on_delete=models.CASCADE)
damaged_quantity = models.IntegerField(default=0)
def __str__(self):
return self.product
class Product(models.Model):
name = models.CharField(max_length=250)
category = models.ForeignKey(Category,on_delete=models.CASCADE)
quantity = models.IntegerField()
views.py I access the queryset of product like this in my views
def list_products(request):
products = Product.objects.annotate(damaged_product_quantity=Sum('damagedproducts__damaged_quantity')).annotate(
real_quantity=ExpressionWrapper(F('quantity') - F('damaged_product_quantity'), output_field=IntegerField()))
list_product_template. Here while displaying the real_quantity if the damage.damaged_quanity and the product.quantity are euqal then it doesnot changes the value.Instead of becomming Zero it doesnot change the value.In other case it is working fine.
{% if not product.real_quantity %}
{{product.quantity}}
{% elif product.real_quantity == product.quantity %}
0
{% else %}
{{ product.real_quantity }}
{% endif %}
product_detail page
def product_detail(request, slug):
product = get_object_or_404(Product, slug=slug)
damaged = Damaged.objects.all()
return render(request, 'pos/product_detail.html', {'product': product,'damaged':damaged})
product_detail template.I tried like this to get the current quantity of products after adding damaged_products but it is nt working well.It is giving me both {% if %} and {% else %} part.How can i solve this?
product quantity:
{% for damage in damaged %}
{% if product.id == damage.product_id %}
{{product.quantity|subtract:damage.damaged_quantity}}
{% else %}
{{product.quantity}}
{% endif %}
{% endfor %}

I think you need to override the save method in Damaged model:
class Damaged(models.Model):
product = models.ForeignKey('Product', on_delete=models.CASCADE)
damaged_quantity = models.IntegerField(default=0)
def __str__(self):
return self.product
def save(self, *args, **kwargs):
super(Damaged, self).save(*args, **kwargs)
self.product.quantity = self.product.quantity - self.damaged_quantity
self.product.save()
But this solution might be inconsistent. For example, if you try to update the Damaged model, then value of the product will be updated again.
I would recommend using annotation to attach value with Product, so that you can query if needed. For example:
For this, lets add a related_name field in Damaged model:
class Damaged(models.Model):
product = models.ForeignKey('Product', on_delete=models.CASCADE, related_name='damagedproducts')
damaged_quantity = models.IntegerField(default=0)
Usage:
from django.db.models import Sum, F, IntegerField
products = Product.objects.annotate(damaged_product_quantity=Sum('damagedproducts__damaged_quantity')).annotate(real_quantity=ExpressionWrapper(F('quantity') - F('damaged_product_quantity'), output_field=IntegerField())
real_quantity_more_than_ten = products.filter(real_quantity__gt=10)
for p in real_quantity_more_than_ten:
print(p.real_quantity)
Update
from django.db.models import Sum
def product_detail(request, slug):
product = get_object_or_404(Product, slug=slug)
damaged = product.productdamaged.all()
if damaged.exists():
damage_amount = damaged.aggregate(d_amount = Sum('productdamaged__damaged_quantity')).get('d_amount', 0)
else:
damage_amount = 0
return render(request, 'pos/product_detail.html', {'product': product,'damage_amount':damage_amount})
# template
{% if damage_amount != 0 %}
{{product.quantity|subtract:damage_amount}}
{% else %}
{{product.quantity}}
{% endif %}

Related

Django: how to show related model fields in template

I'm new in Django 3.0 and I'm lost in this easy question, please help me.
I have 2 models:
class Product(models.Model):
fields...
class ProductType(models.Model):
product = models.ForeignKey(Product, related_name='product_types', on_delete=models.CASCADE)
color = models.Charfield(...)
In my template, I would like to show all the related product types and their fields to a specific product:
...
{% for product in products %}
{{ product.??? }}
{% endfor %}
Here is my view:
class ProductsView(ListView):
collection = None
model = Product
paginate_by = 6
template_name = 'shop/product/list.html'
context_object_name = 'products'
def get_queryset(self):
products = Product.objects.filter(available=True)
collection_name = self.kwargs['collection_name'] if 'collection_name' in self.kwargs else None
if collection_name:
collection = get_object_or_404(Collection, name=collection_name)
products = products.filter(collection=collection)
return products
def get_context_data(self):
context = super().get_context_data(**self.kwargs)
context['notification'] = Notification.objects.all()
if 'collection_name' in self.kwargs:
context['collection'] = get_object_or_404(Collection, name=self.kwargs['collection_name'])
context['collection_name'] = self.kwargs['collection_name']
context['collections'] = Collection.objects.all()
return context
Thank you
You access the related ProductTypes through a manager that has as name the value you specify as related_name=… [Django-doc], so in this case:
{% for product in products %}
{% for type in product.product_types.all %}
{{ type.color }}
{% endfor %}
{% endfor %}
To boost efficiency, you can fetch all related ProductTypes for the elements in the queryset with .prefetch_related(…) [Django-doc]:
class ProductsView(ListView):
# …
def get_queryset(self):
products = Product.objects.prefetch_related('product_types').filter(available=True)
collection_name = self.kwargs['collection_name'] if 'collection_name' in self.kwargs else None
if collection_name:
collection = get_object_or_404(Collection, name=collection_name)
products = products.filter(collection=collection)
return products

django listview filter & get value templates

I made a list of events registered today in the inventory template, and I would like to show the total rating of the events(registered today).
I called it from the template by making the sum of the scores a function, but it is not visible. Does anyone know?
views.py
class CalendarView(generic.ListView):
model = Event
template_name = 'cal/calendar.html'
def get_queryset(self, **kwargs):
return Event.objects.all().filter(start_time__date=date.today())
def filter_event_rating_sum(self):
filtered_event = Event.objects.all().filter(start_time__date=date.today())
sum_rating = 0
for each_event in filtered_event:
sum_rating += each_event.rating
return sum_rating
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
d = get_date(self.request.GET.get('month', None))
cal = Calendar(d.year, d.month)
# issue self.request.user
html_cal = cal.formatmonth(self.request.user, withyear=True)
context['calendar'] = mark_safe(html_cal)
context['prev_month'] = prev_month(d)
context['next_month'] = next_month(d)
return context
templates.html
<p class="today">Today</p>
{% for list in object_list %}
<div class="today_list_item">
<span>{{ list.title }}</span>
<span class="each_rating">{{ list.rating }}</span>
</div>
{% endfor %}
<p class="total">TOTAL</p>
{{ sum_rating }}
</div>
models.py
class Event(models.Model):
title = models.CharField(max_length=200)
start_time = models.DateTimeField(default = timezone.now, blank = True)
# default = timezone.now,
profile=models.ForeignKey(Profile, related_name='event',on_delete=models.CASCADE)
rating = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)], blank=True, default='enter your value')
def __str__(self):
return '{}/ {}/ {}'.format(self.id, self.title, self.start_time, self.rating)
you can only use those variables which are in the dictionary returned by get_context_data function. Add this code in get_context_data function like this
queryset['sum_rating'] = self.filter_event_rating_sum()

Django and aggregating grand-child records

I am new to Django but have been around RdB for a while. I am finally getting the hang of model-view-template. I am struggling a little on "aggregate" and "annotate" especially when my model has grand-child records and I want aggregate.
I use Django 3 on Python 3.
Here is my example setup, I need help straightening it out. I am all sorts of wrong.
There are stores, each that served many pizzas, each pizza has many toppings, each topping used a different qty of items. I want to know the total topping qty for each pizza made and for total topping qty for each store.
models.py
class Parlor(models.Model):
name = models.CharField(max_length=64)
class Pizza(models.Model):
name = models.CharField(max_length=64)
store = models.ForeignKey(Parlor, on_delete=models.CASCADE)
class Topping(models.Model):
name = models.CharField(max_length=64)
pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)
qty = models.IntegerField(default=0)
views.py
class ParlorDetail(generic.DetailView):
model = Parlor
template_name = 'pizza/parlor_detail.html'
context_object_name = 'parlor'
def get_context_data(self, **kwargs):
context = super(ParlorDetail, self).get_context_data(**kwargs)
id = self.kwargs['pk']
topping_qty = Pizza.objects.filter(parlor=id).annotate(sum=Sum('qty')).aggregate(sum=Sum('qty'))
return context
class PizzaDetail(generic.DetailView):
model = Pizza
template_name = 'pizza/pizza_detail.html'
context_object_name = 'pizza'
def get_context_data(self, **kwargs):
context = super(PizzaDetail, self).get_context_data(**kwargs)
id = self.kwargs['pk']
topping_qty = Topping.objects.filter(pizza=id).annotate(sum=Sum('qty'))
return context
parlor_detail.html
{% extends "pizza/my_base.html" %}
{% block content %}
<div>Parlor: {{ name }}</div>
<div>Pizzas Made at Parlor</div>
{% for pizza in pizzas.all %}
<div>Pizza: {{ pizza.name }}</div>
<div>Toppings: {{ pizza.topping_qty.sum }}</div>
{% endfor %}
<div> Total Qty of Toppings For Parlor: pizzas.topping_qty </div>
{% end block content %}

Two layer for loops to demonstrate list in django template [duplicate]

models.py
class Task(models.Model):
level = models.ForeignKey(Level, on_delete=models.CASCADE)
todo = models.ForeignKey(ToDo, on_delete=models.CASCADE)
student = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=150)
content = models.TextField()
timestamp = models.TimeField(auto_now=True)
datestamp = models.DateField( auto_now=True)
like = models.ManyToManyField(User,related_name='user_likes', blank=True)
is_verified=models.BooleanField(default=False, blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('student:task-detail', kwargs={'pk': self.pk})
objects = PostManager()
#property
def comments(self):
instance = self
qs = Comment.objects.filter_by_instance(instance)
return qs
#property
def get_content_type(self):
instance = self
content_type = ContentType.objects.get_for_model(instance.__class__)
return content_type
class Images(models.Model):
post = models.ForeignKey(Task, default=None,on_delete=models.CASCADE)
image = models.ImageField(verbose_name='Image',blank=True)
def __str__(self):
return self.post.title
I have two models Task and Images. Im storing multiple images for a task saved . I want to display the list of tasks using pagination and also images inside each task.
views.py:
#login_required(login_url='/account/login/')
#page_template('student_dash_page.html')
def StudentDashView(request,template='student_dash.html', extra_context=None):
if not request.user.is_authenticated:
return redirect('accounts:index')
task = Task.objects.all().order_by('timestamp')
images = Images.objects.filter(post=task)
notifications = Notification.objects.filter(receiver=request.user).order_by('-timestamp')
page = request.GET.get('page', 1)
paginator = Paginator(task, 10)
try:
tasks = paginator.page(page)
except PageNotAnInteger:
tasks = paginator.page(1)
except EmptyPage:
tasks= paginator.page(paginator.num_pages)
context = {
'notifications': notifications,
'nbar': 'home',
'task': tasks,
'images': images
}
if not request.user.is_client:
return HttpResponse("You are in trainer account")
if extra_context is not None:
context.update(extra_context)
return render(request, template, context)
How do i get the images to display correctly inside the template using for loops
Im trying
{% for obj in task %}
<p>{{ obj.title }}
{% for image in images %}
<img src="{{ image.url }}"</img>
{% endfor %}
{% endfor %}
Im getting the error: The QuerySet value for an exact lookup must be limited to one result using slicing.
This line doesn't make any sense:
images = Images.objects.filter(post=task)
because task is a queryset of all the Task instances.
You don't need to get the images at all in the view. Remove that line and the other references, and just do this in the template:
{% for obj in task %}
<p>{{ obj.title }}</p>
{% for image in obj.images_set.all %}
<img src="{{ image.image.url }}"</img>
{% endfor %}
{% endfor %}
Note also, the Image object has a field called image, and that's what you need to access the url attribute on.
(For the sake of database efficiency, you might want to change your query slightly in the view:
task = Task.objects.all().order_by('timestamp').prefetch_related('images_set')
otherwise every iteration will cause a separate db call to get the related images. You don't need to do this to make things work, though.)

What is the best way to display data in a template in Django?

Given the below model and view, for any given club I am trying to display that club's available courts ("court") and available times ("avail_time") in the template. I am having trouble doing this.
Model:
from django.db import models
class Club(models.Model):
establishment = models.CharField(max_length=200)
address = models.CharField(max_length=200)
def __unicode__(self):
return self.establishment
class Available(models.Model):
club = models.ForeignKey(Club)
court = models.CharField(max_length=200)
avail_time = models.DateTimeField('available time')
def __unicode__(self):
return self.court
class Taken(models.Model):
club = models.ForeignKey(Club)
court = models.ForeignKey(Available)
taken_time = models.DateTimeField('taken time')
userid = models.EmailField(max_length = 75)
View:
def avail_times(request, club_id):
p = get_object_or_404(Club,pk=club_id)
return render_to_response('reserve/templates/avail_times.html', {'club':p})
Template:
{% for court in club.court_set.all %}
{{court.court }}
{% endfor %}
Well, you don't seem to have a Court model, so I'm not sure why you're trying to call court_set.all. You could use club.available_set.all to show the list of Available instances for that club, which might be what you mean.
First step would be to set up your models appropriately. Clubs have Courts and Courts have Available Times. Clubs don't have Available Times, which is how you have it set up now. Further, "taken" is a status of an available time; it shouldn't be a model itself. Try something like:
class Club(models.Model):
establishment = models.CharField(max_length=200)
address = models.CharField(max_length=200)
def __unicode__(self):
return self.establishment
class Court(models.Model):
club = models.ForeignKey(Club, related_name='courts')
name = models.CharField(max_length=200)
class CourtTime(models.Model):
AVAILABLE = 0
TAKEN = 1
STATUS_CHOICES = (
(AVAILABLE, 'Available'),
(TAKEN, 'Taken'),
)
court = models.ForeignKey(Club, related_name='times')
time = models.DateTimeField('available time')
status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, default=STATUS_CHOICES[AVAILABLE])
def __unicode__(self):
return self.court
Then, I would suggest a custom manager on CourtTime to return available/taken querysets:
class CourtTimeQuerySet(models.query.QuerySet):
def available(self):
return self.filter(status=CourtTime.STATUS_CHOICES[CourtTime.AVAILABLE])
def taken(self):
return self.filter(status=CourtTime.STATUS_CHOICES[CourtTime.TAKEN])
class CourtTimeManager(models.Manager):
use_for_related_fields = True
def get_query_set(self, *args, **kwargs):
return CourtTimeQuerySet(self.model)
def available(self, *args, **kwargs):
return self.get_query_set().available(*args, **kwargs)
def taken(self, *args, **kwargs):
return self.get_query_set().taken(*args, **kwargs)
Then, add it to your model:
class CourtTime(models.Model):
...
objects = CourtTimeManager()
With all that in place, you can just do the following in your template:
{% for court in club.courts.all %}
<h2>{{ court.name }}</h2>
<ul>
{% for time in court.times.available %}
<li>{{ time|date:"m/d/Y g:i A" }}</li>
{% endfor %}
</ul>
{% endfor %}