Model Design for Orders in Django

A simple model design for Order and order items in Django


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( + str( + str( + '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( + str( + str( + str(new_order_id_int).zfill(4)
  return new_order_id

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

  PAID = 1

    (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('0.01'))

    return str(total -

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' % (

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

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

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

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


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. 9 Ways to Boost the Design of Your Sports Team Website

  2. DevOps Tools

  3. The Best Marketing Apps to Use with Shopify

  4. Tips to Increase Software Development Speed

  5. Mitigating Risks In Custom Software Development


News Letter

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