pythondjangodjango-modelsdjango-templates

django RelatedManager return None in template


I am trying to access related data in Templates But I only get None.

models

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

class Product(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField()
    price = models.PositiveBigIntegerField()
    discount = models.PositiveBigIntegerField(default=0)
    inventory = models.PositiveBigIntegerField(default=1)
    last_update =  models.DateTimeField(auto_now_add=True)
    def __str__(self) -> str:
        return self.title

class Image(models.Model):
    image = models.ImageField()
    product = models.ForeignKey(to=Product,on_delete=models.CASCADE)
    
    
class Cart(models.Model):
    
    STATUS = [
        (0,"pending payment"),
        (1,"paid")
              ]
    
    status = models.SmallIntegerField(choices=STATUS,default=0)
    user = models.ForeignKey(to=User,on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now=True)
    
    def __str__(self) -> str:
        return f"{self.user} - {self.status}"
    
@receiver(post_save,sender=Cart)
def cart_post_save(sender, instance, created, *args, **kwargs):
    if created and instance.status == 1 :
        Cart.objects.create(user=instance.user)

    
        

class Order(models.Model):
    product = models.ForeignKey(to=Product,on_delete=models.CASCADE)
    count = models.PositiveIntegerField(default=0)
    cart = models.ForeignKey(to=Cart,on_delete=models.CASCADE)
    
    def __str__(self) -> str:
        return f"{self.product}"

views


from django.views import generic 
from . import models
from django.http import JsonResponse,HttpResponseBadRequest,HttpResponse

class ProductsList(generic.ListView):
    """return list of all products and template name is prudoct_list.html"""
    model = models.Product
    paginate_by = 30
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context
    
class ProductsDetail(generic.DetailView):
    """return a product and template name is prudoct_detail.html"""
    model = models.Product

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

base.html



{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>online-shop</title>
    
</head>
<body>
    <nav>
        {% if request.user.is_anonymous %}

        {% else %}
            {{request.user}}
            <form method="post" action="{% url 'logout' %}">
                {% csrf_token %}
                <button type="submit">logout</button>
            </form>
            <a href="{% url 'cart' %}">cart</a>
            
        {% endif %}

    </nav>
    <script src="{% static 'js/jquery-3.7.1.min.js' %}"></script>
    {% block content %}
    
    {% endblock content %}

    
</body>
</html>

product_detail.html

{% extends "base.html" %}

{% block content %}

{% for image in object.image_set.all %}
    <img src="{{image.image.url}}" alt="">
{% endfor %}
<div>title : {{object.title}}</div>
<div>description : {{object.description}}</div>
<div>price : {{object.price}}</div>
<div>discount : {{object.discount}}</div>
<div>last_update : {{object.last_update}}</div>

**{{object.order_set.first}}** # returns None

{% endblock content %}

I expect first order in {{object.order_set.first}} and also RelatedManager work fine for images

{% for image in object.image_set.all %}
    <img src="{{image.image.url}}" alt="">
{% endfor %} 

but for orders I only get None. the output in product_detail is :

title : test123 description : some text here price : 12345 discount : 0 last_update : Aug. 9, 2024, 7:03 p.m. None

also if i change {{object.order_set.first}} to {{object.order_set}} the output will be

title : test123 description : some text here price : 12345 discount : 0 last_update : Aug. 9, 2024, 7:03 p.m. stor.Order.None

update

{{object.order_set.all}}

return -> <QuerySet []> and also

{% for order in object.order_set.all %}
{{order}}
{% endfor %}

returns nothing because of <QuerySet []> is empty

python version -> 3.10.11 Django version -> 5.1


Solution

  • You get None for all related managers. You can use {{ object.order_set.all }} to turn it into a queryset that will print (part) of the items.

    But {{ object.order_set }} simply makes not much sense, even if it would print the records, then it would generate <QuerySet [order1, order2]> which is quite ugly.

    Enumerate over the relation and format the orders properly:

    {% extends "base.html" %}
    {% block content %}
    
    {% for image in object.image_set.all %}
       <img src="{{image.image.url}}" alt="">
    {% endfor %}
    <div>title :{{object.title}}</div>
    <div>description : {{object.description}}</div>
    <div>price : {{object.price}}</div>
    <div>discount : {{object.discount}}</div>
    <div>last_update : {{object.last_update}}</div>
    
    {% for order in object.order_set.all %}
        <!-- ..
       -->
    {% endfor %}
    {% endblock content %}