djangodjango-modelsdjango-database

How to write out an object from a relationship in django


I don't know how to describe this exactly in database jargon. I would like to output an object that is in a relationship with another like this. order__orderitem.product.title

models.py

class Order(models.Model):
    status_types = [
        ("Ordered", "Ordered"),
        ("Sent", "Sent"),
        ("Delivered", "Delivered"),
        ("Extended", "Extended"),
        ("Returned", "Returned"),
    ]
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    order_date = models.DateTimeField()
    return_date = models.DateTimeField(null=True)
    status = models.CharField(choices=status_types, default="Ordered", max_length=100)
    total = models.IntegerField(null=False)
    payment = models.OneToOneField(Payment, on_delete=models.CASCADE, null=False, blank=False)
    shipping = models.ForeignKey(Shipping, on_delete=models.CASCADE, null=False, blank=False)
    first_name = models.CharField(max_length=255, null=False, blank=False)
    last_name = models.CharField(max_length=255, null=False, blank=False)
    phone = models.CharField(max_length=12, null=False, blank=False)
    city = models.CharField(max_length=255, null=False, blank=False, default=None)
    zip_code = models.CharField(max_length=10, null=False, blank=False, default=None)
    street = models.CharField(max_length=255, null=False, blank=False, default=None)
    building_number = models.CharField(max_length=10, null=False, blank=False, default=None)
    apartment_number = models.CharField(max_length=10, null=True, blank=True, default=None)


class OrderItem(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
    price = models.IntegerField(null=False, blank=False, default=15)
    debt = models.IntegerField(null=True, default=0)

orders.html

{% for item in object_list %}
    {% for it in item__OrderItem %}
                    {{ it.product.title }}
    {% endfor %}
{% endfor %}

Is it possible in such a way?


Solution

  • Yes, you work with:

    {% for item in object_list %}
        {% for it in item.orderitem_set.all %}
            {{ it.product.title }}
        {% endfor %}
    {% endfor %}

    In the view, it is better to prefetch the items already, to prevent an N+1 problem with:

    from django.db.models import Prefetch
    
    
    class MyListView(ListView):
        model = Order
        queryset = Order.objects.prefetch_related(
            Prefetch('orderitem_set', OrderItem.objects.select_related('product'))
        )

    while not necessary, this will result in two queries, whereas without this, it will require m×n+n+1 queries with N the number of Orders and m the number of OrderItems.