Model Design for Orders in Django

A simple model design for Order and order items in Django

Advert

Billing or orders management is a typical use case in most applications, there are many Saas solutions for this but still there can be situations where you need an in-house solution, and it can be tricky and time-consuming to make a design thats efficient and needs least queries. This is a basic model design you may add or modify this as per requirement.

The design includes 4 models

  • Items : Stores the items that can be order. Not required but provides consistency.
  • Order: Stores order information and functions ( Total, Subtotal, etc).
  • Order Items: Stores order items information.


import datetime

class Items(models.Model):
  name = models.CharField(max_length=200, null=False)
  price = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
  active = models.BooleanField(default=True)

  # Records
  created = models.DateTimeField(auto_now_add=True)
  time = models.DateTimeField(auto_now=True)

def increment_order_id():
  """ Creates Order ID of format  ABCD  . Change as per neeed."""
  prefix = 'ABCD'  
  # if you are gonna change it but its not 4 character long 
  # make sure to change the numbers below too
  last_order = Order.objects.all().order_by('id').last()
  if not last_order:
    return str(prefix) + str(datetime.date.today().year) + str(
        datetime.date.today().month).zfill(2) + str(
        datetime.date.today().day).zfill(2) + '0000'
  order_id = last_order.order_id
  order_id_int = int(order_id[12:16])
  new_order_id_int = order_id_int + 1
  new_order_id =  str(prefix) + str(str(datetime.date.today().year)) + str(
      datetime.date.today().month).zfill(2) + str(
      datetime.date.today().day).zfill(2) + str(new_order_id_int).zfill(4)
  return new_order_id


class Order(models.Model):
    """ Order Model """

  NOTPAID = 0
  PAID = 1
  PARTPAID = 2

  PAYMENT_STATUS = (
    (NOTPAID, 'Not Paid'),
    (PARTPAID, 'Partial Paid'),
    (PAID, 'Paid'),
  )

  order_id = models.CharField(max_length=20, default=increment_order_id, null=True, blank=True, editable=False)
  payment_status = models.IntegerField(default=NOTPAID, choices=PAYMENT_STATUS, null=False)
  lock = models.BooleanField(default=False, null=False)
  discount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
  created = models.DateTimeField(auto_now_add=True)
  time = models.DateTimeField(auto_now=True)

  class Meta:
    ordering = ('-created', '-id')

  def __str__(self):
    return '%s' % (self.order_id)

  def subtotal(self):
    total = Decimal('0.00').quantize(Decimal('0.01'))
    for item in self.orderitems.all().filter(status=True):
      total = total + Decimal(item.subtotal()).quantize(Decimal('0.01'))
    return str(total)

  def total(self):
    total = Decimal('0.00').quantize(Decimal('0.01'))
    for item in self.orderitems.all().filter(status=True):
      total = total + Decimal(item.total()).quantize(Decimal('0.01'))

    return str(total - self.discount)


class OrderItems(models.Model):
  order = models.ForeignKey(Order, on_delete=models.PROTECT,
                            related_name='orderitems', null=True)
  desc = models.CharField(max_length=500, null=True)

  # Item
  item = models.ForeignKey(Items, on_delete=models.PROTECT, null=True)
  price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
  quantity = models.IntegerField(default=1, null=False)
  tax = models.DecimalField(max_digits=10, decimal_places=4, default=0.00)
  discount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)

  # Records
  created = models.DateTimeField(auto_now_add=True)
  time = models.DateTimeField(auto_now=True)

  def __str__(self):
    return '%s' % (self.id)

  def description(self):
    # If items is linked, return item's description
    if self.item:
      return str(self.item.name)
    else:
      return 'Order Item'

  def subtotal(self):
    total = ((self.price * Decimal(self.quantity)).quantize(
        Decimal('0.01')) - self.discount)
    return str(total)

  def taxtotal(self):
    subtotal = Decimal(self.subtotal()).quantize(Decimal('0.01'))
    total = subtotal * self.tax
    return str(Decimal(total).quantize(Decimal('0.01')))

  def total(self):
    total = Decimal(self.subtotal()).quantize(Decimal('0.01')) + Decimal(
        self.taxtotal()).quantize(Decimal('0.01'))
    return str(total)

Comments

Wow ! you have someting to tell us. That's great! Please keep in mind that comments are moderated, we employ rel="nofollow" for links, avoid using a spammy word or a domain in name field, it might end up as a Spam. Thanks for reading.

Last 5 Articles

All Articles >

  1. Server Side Render ReactJS Application

     
  2. How to Deploy React JS application

     
  3. Environment Variables in React JS

     
  4. Multiple Serialisers in Django ModelViewSet

     
  5. Security Myths

     

News Letter

Subscribe to our email newsletter for useful tips and valuable resources, sent out every new article release.