PacktPublishing / Django-5-By-Example

Django 5 By Example (5th Edition) published by Packt
https://djangobyexample.com/
MIT License
244 stars 106 forks source link

The shop example (ch 8), the orders model has no items #24

Open stevej2608 opened 4 months ago

stevej2608 commented 4 months ago

The Order model has no items field.

models.py

class Order(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    email = models.EmailField()
    address = models.CharField(max_length=250)
    postal_code = models.CharField(max_length=20)
    city = models.CharField(max_length=100)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    paid = models.BooleanField(default=False)

    class Meta:
        ordering = ['-created']
        indexes = [
            models.Index(fields=['-created']),
        ]

    def __str__(self):
        return f'Order {self.id}'

    def get_total_cost(self):
        return sum(item.get_cost() for item in self.items.all())

get_total_cost() references self.items but it's not defined as a field?

HBarotov commented 4 months ago

Hi,

This is a ForeignKey field. self.items.all is referring to its child model OrderItem. There is an OrderItem model beneath:

class OrderItem(models.Model):
    order = models.ForeignKey(Order, related_name="items" , on_delete=models.CASCADE)
    product = models.ForeignKey(
        Product, related_name="order_items", on_delete=models.CASCADE
    )
    price = models.DecimalField(max_digits=10, decimal_places=2)
    quantity = models.PositiveIntegerField(default=1)

    def __str__(self):
        return str(self.id)

    def get_cost(self):
        return self.price * self.quantity

The OrderItem is the child of the model Order. In Django, the default way is to access the child model this way:

self.orderitem_set.all()

As the related_name is set to items, we can access the child model using the given syntax.

class OrderItem(models.Model):
    order = models.ForeignKey(Order, related_name="items" , on_delete=models.CASCADE)