Registering customer orders

When a shopping cart is checked out, you need to save an order into the database. Orders will contain information about customers and the products they are buying.

Create a new application for managing customer orders using the following command:

python manage.py startapp orders

Edit the settings.py file of your project and add 'orders' to the INSTALLED_APPS setting as follows:

INSTALLED_APPS = (
    # ...
    'orders',
)

You have activated the new application.

Creating order models

You will need a model to store the order details, and a second model to store items bought, including their price and quantity. Edit the models.py file of the orders application and add the following code to it:

from django.db import models
from shop.models import Product

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',)

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

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


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

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

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

The Order model contains several fields for customer information and a paid boolean field, which defaults to False. Later on, we are going to use this field to differentiate between paid and unpaid orders. We also define a get_total_cost() method to obtain the total cost of the items bought in this order.

The OrderItem model allows us to store the product, quantity, and price paid for each item. We include get_cost() to return the cost of the item.

Run the next command to create initial migrations for the orders application:

python manage.py makemigrations

You will see the following output:

Migrations for 'orders':
  0001_initial.py:
    - Create model Order
    - Create model OrderItem

Run the following command to apply the new migration:

python manage.py migrate

Your order models are now synced to the database.

Including order models in an administration site

Let's add the order models to the administration site. Edit the admin.py file of the orders application to make it look like this:

from django.contrib import admin
from .models import Order, OrderItem

class OrderItemInline(admin.TabularInline):
    model = OrderItem
    raw_id_fields = ['product']

class OrderAdmin(admin.ModelAdmin):
    list_display = ['id', 'first_name', 'last_name', 'email', 
                    'address', 'postal_code', 'city', 'paid', 
                    'created', 'updated']
    list_filter = ['paid', 'created', 'updated']
    inlines = [OrderItemInline]
    
admin.site.register(Order, OrderAdmin)

We use a ModelInline for the OrderItem model to include it as an inline in the OrderAdmin class. An inline allows you to include a model for appearing on the same edit page as the parent model.

Run the development server with the command python manage.py runserver, and then open http://127.0.0.1:8000/admin/orders/order/add/ in your browser. You will see the following page:

Including order models in an administration site

Creating customer orders

We need to use the order models that we just created to persist the items contained in the shopping cart when the user finally wishes to place an order. The functionality for creating a new order will work as follows:

  1. We present users an order form to fill in their data.
  2. We create a new Order instance with the data entered by users, and then we create an associated OrderItem instance for each item in the cart.
  3. We clear all the cart contents and redirect users to a success page.

First, we need a form to enter order details. Create a new file inside the orders application directory and name it forms.py. Add the following code to it:

from django import forms
from .models import Order

class OrderCreateForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = ['first_name', 'last_name', 'email', 'address', 
                  'postal_code', 'city']

This is the form that we are going to use for creating new Order objects. Now, we need a view to handle the form and create a new order. Edit the views.py file of the orders application and add the following code to it:

from django.shortcuts import render
from .models import OrderItem
from .forms import OrderCreateForm
from cart.cart import Cart

def order_create(request):
    cart = Cart(request)
    if request.method == 'POST':
        form = OrderCreateForm(request.POST)
        if form.is_valid():
            order = form.save()
            for item in cart:
                OrderItem.objects.create(order=order,
                                        product=item['product'],
                                        price=item['price'],
                                        quantity=item['quantity'])  
            # clear the cart
            cart.clear()
            return render(request,
                          'orders/order/created.html',
                          {'order': order})
    else:
        form = OrderCreateForm()
    return render(request,
                  'orders/order/create.html',
                  {'cart': cart, 'form': form})

In the order_create view, we will obtain the current cart from the session with cart = Cart(request). Depending on the request method, we will perform the following tasks:

  • The GET request: This instantiates the OrderCreateForm form and renders the template orders/order/create.html.
  • The POST request: This validates the data that get posted. If the data is valid, we will use order = form.save() to create a new Order instance. We will then save it to the database, and then store it in the order variable. After creating the order, we will iterate over the cart items and create OrderItem for each of them. Finally, we will clear the cart contents.

Now, create a new file inside the orders application directory and name it urls.py. Add the following code to it:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^create/$',
        views.order_create,
        name='order_create'),
]

This is the URL pattern for the order_create view. Edit the urls.py file of myshop and include the following pattern. Remember to place it before the shop.urls pattern:

url(r'^orders/', include('orders.urls', namespace='orders')),

Edit the cart/detail.html template of the cart application and replace this line:

<a href="#" class="button">Checkout</a>

Replace this with the following ones:

<a href="{% url "orders:order_create" %}" class="button">
  Checkout
</a>

Users can now navigate from the cart detail page to the order form. We still need to define templates for placing orders. Create the following file structure inside the orders application directory:

templates/
    orders/
        order/
            create.html
            created.html

Edit the orders/order/create.html template and include the following code:

{% extends "shop/base.html" %}

{% block title %}
  Checkout
{% endblock %}

{% block content %}
  <h1>Checkout</h1>
    
  <div class="order-info">
    <h3>Your order</h3>
    <ul>
      {% for item in cart %}
        <li>
          {{ item.quantity }}x {{ item.product.name }} 
          <span>${{ item.total_price }}</span>
        </li>
      {% endfor %}
    </ul>
    <p>Total: ${{ cart.get_total_price }}</p>
  </div>
    
  <form action="." method="post" class="order-form">
    {{ form.as_p }}
    <p><input type="submit" value="Place order"></p>
    {% csrf_token %}
  </form>
{% endblock %}

This template displays the cart items including totals and the form to place an order.

Edit the orders/order/created.html template and add the following code:

{% extends "shop/base.html" %}

{% block title %}
  Thank you
{% endblock %}

{% block content %}
  <h1>Thank you</h1>
  <p>Your order has been successfully completed. Your order number is <strong>{{ order.id }}</strong>.</p>
{% endblock %}

This is the template that we render when the order is successfully created. Start the web development server to track new files. Open http://127.0.0.1:8000/ in your browser, add a couple of products to the cart, and continue to checkout the page. You will see a page like the following one:

Creating customer orders

Fill in the form with the valid data and click on Place order button. The order will be created and you will see a success page like this:

Creating customer orders
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset