1

I am very new to Django and tried various answered questions on this forum. But I could not display the TITLE of the Product. I want to display the TITLE for my product from the DB.

From models.py :

class Product(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField()
    description = models.TextField()
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)
    inventory = models.IntegerField()
    last_update = models.DateTimeField(auto_now=True)
    collection = models.ForeignKey(Collection, on_delete=models.PROTECT)
    promotions = models.ManyToManyField(Promotion)


class Order(models.Model):
    PAYMENT_STATUS_PENDING = 'P'
    PAYMENT_STATUS_COMPLETE = 'C'
    PAYMENT_STATUS_FAILED = 'F'
    PAYMENT_STATUS_CHOICES = [
        (PAYMENT_STATUS_PENDING, 'Pending'),
        (PAYMENT_STATUS_COMPLETE, 'Complete'),
        (PAYMENT_STATUS_FAILED, 'Failed')
    ]

    placed_at = models.DateTimeField(auto_now_add=True)
    payment_status = models.CharField(
        max_length=1, choices=PAYMENT_STATUS_CHOICES, default=PAYMENT_STATUS_PENDING)
    customer = models.ForeignKey(Customer, on_delete=models.PROTECT)

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.PROTECT)
    product = models.ForeignKey(Product, on_delete=models.PROTECT)
    quantity = models.PositiveSmallIntegerField()
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)

From views.py :

order = Order.objects.select_related('customer').prefetch_related('orderitem_set__product').order_by('-placed_at')[:5]

From hello.html :

{% for prod in order %}
      <li>Order ID : {{ prod.id }} -- Customer {{ prod.customer.first_name }} -- Product {{ prod.orderitem_set.product.title }}</li>

I have 2 questions here:

  1. In hello.html : How do I display the Product Title?
  2. In the views.py : How do I load and display the promotions from the product class in same call?

Expected output :

Order ID : 408 -- Customer Olin -- Product -- Cheese -- Promotion : xyz
Order ID : 513 -- Customer Merna -- Product -- Milk -- Promotion : xyz
Order ID : 711 -- Customer Rubi -- Product -- Biscuits -- Promotion : xyz
Order ID : 2 -- Customer Nicko -- Product -- Curd -- Promotion : xyz
Order ID : 248 -- Customer Shandeigh -- Product -- Butter -- Promotion : xyz
Ai_Nebula
  • 39
  • 9

1 Answers1

2

The reason it didn't work was because you had more than one orderitem for your order. So you need to add all and then an index.

Change this

<li>Order ID : {{ prod.id }} -- Customer {{ prod.customer.first_name }} -- Product {{ prod.orderitem_set.product.title }}</li>

To this

<li>Order ID : {{ prod.id }} -- Customer {{ prod.customer.first_name }} -- Product {{ prod.orderitem_set.all.0.product.title }}</li>

Maybe you want to loop over the orderitems instead?

views.py

orderObjs = Order.objects.select_related('customer').prefetch_related('orderitem_set__product').order_by('-placed_at')[:5]

orderitems = [item for order in orderObjs for item in order.orderitem_set.all()]

context = {
    "orderitems": orderitems
}

In your html file

{% for orderitem in orderitems %}
    <li>Order ID : {{ orderitem.order.id }} -- Customer {{ orderitem.order.customer.first_name }} -- Product {{ orderitem.product.title }}</li>
{% endfor %}
AnonymousUser
  • 690
  • 7
  • 26
  • There's no need to retrieve `OrderItem`s in a loop, which gives us another N trips to the database, since we already prefetched the `orderitem_set` in the `orderObjs`. Moreover, the `order` is a foreign key relation, there could be more than one `OrderItem` with the same `oder_id`, which will lead to `MultipleObjectsReturned` exception – Savva Surenkov Feb 17 '22 at 06:19
  • 2
    Simply put the `orderitems = [item for order in orderObjs for item in order.orderitem_set.all()]` comprehension to flatten items. – Savva Surenkov Feb 17 '22 at 06:28
  • When I change to your suggested code piece, I see in my SQL debugger, my queries go from 5 to 17. I get the desired output. But one an extended cost of multiple queries. Is there an better way to do it? I understand why the SQL queries shot up. – Ai_Nebula Feb 19 '22 at 06:53
  • @AmitabhSuman On your "Expected output", each order only have 1 Product. So do you want to use **OneToOneField**? – AnonymousUser Feb 20 '22 at 07:18
  • If you add OneToOneField to the order and product in the OrderItem model, then an order would only be able to have 1 Product. https://docs.djangoproject.com/en/4.0/topics/db/examples/one_to_one/ – AnonymousUser Feb 20 '22 at 07:32