Extending the admin site with custom views

Sometimes, you may want to customize the administration site beyond what is possible through configuring ModelAdmin, creating admin actions, and overriding admin templates. If this is the case, you need to create a custom admin view. With a custom view, you can build any functionality you need. You just have to make sure that only staff users can access your view and that you maintain the admin look and feel by making your template extend an admin template.

Let's create a custom view to display information about an order. Edit the views.py file of the orders application and add the following code to it:

from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import get_object_or_404
from .models import Order

@staff_member_required
def admin_order_detail(request, order_id):
order = get_object_or_404(Order, id=order_id)
return render(request,
'admin/orders/order/detail.html',
{'order': order})

The staff_member_required decorator checks that both the is_active and is_staff fields of the user requesting the page are set to True. In this view, we get the Order object with the given ID and render a template to display the order.

Now, edit the urls.py file of the orders application and add the following URL pattern to it:

path('admin/order/<int:order_id>/', views.admin_order_detail, name='admin_order_detail'),

Create the following file structure inside the templates/ directory of the orders application:

admin/ 
orders/
order/
detail.html

Edit the detail.html template and add the following content to it:

{% extends "admin/base_site.html" %}
{% load static %}

{% block extrastyle %}
<link rel="stylesheet" type="text/css" href="{% static "css/admin.css" %}" />
{% endblock %}

{% block title %}
Order {{ order.id }} {{ block.super }}
{% endblock %}

{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url "admin:index" %}">Home</a> &rsaquo;
<a href="{% url "admin:orders_order_changelist" %}">Orders</a>
&rsaquo;
<a href="{% url "admin:orders_order_change" order.id %}">Order {{ order.id }}</a>
&rsaquo; Detail
</div>
{% endblock %}

{% block content %}
<h1>Order {{ order.id }}</h1>
<ul class="object-tools">
<li>
<a href="#" onclick="window.print();">Print order</a>
</li>
</ul>
<table>
<tr>
<th>Created</th>
<td>{{ order.created }}</td>
</tr>
<tr>
<th>Customer</th>
<td>{{ order.first_name }} {{ order.last_name }}</td>
</tr>
<tr>
<th>E-mail</th>
<td><a href="mailto:{{ order.email }}">{{ order.email }}</a></td>
</tr>
<tr>
<th>Address</th>
<td>{{ order.address }}, {{ order.postal_code }} {{ order.city }}</td>
</tr>
<tr>
<th>Total amount</th>
<td>${{ order.get_total_cost }}</td>
</tr>
<tr>
<th>Status</th>
<td>{% if order.paid %}Paid{% else %}Pending payment{% endif %}</td>
</tr>
</table>

<div class="module">
<div class="tabular inline-related last-related">
<table>
<h2>Items bought</h2>
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{% for item in order.items.all %}
<tr class="row{% cycle "1" "2" %}">
<td>{{ item.product.name }}</td>
<td class="num">${{ item.price }}</td>
<td class="num">{{ item.quantity }}</td>
<td class="num">${{ item.get_cost }}</td>
</tr>
{% endfor %}
<tr class="total">
<td colspan="3">Total</td>
<td class="num">${{ order.get_total_cost }}</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endblock %}

This is the template to display an order detail on the administration site. This template extends the admin/base_site.html template of Django's administration site, which contains the main HTML structure and CSS styles of the admin. We load the custom static file css/admin.css.

In order to use static files, you need to get them from the code that came with this chapter. Copy the static files located in the static/ directory of orders application and add them to the same location in your project.

We use the blocks defined in the parent template to include our own content. We display information about the order and the items bought.

When you want to extend an admin template, you need to know its structure and identify existing blocks. You can find all admin templates at https://github.com/django/django/tree/2.0/django/contrib/admin/templates/admin.

You can also override an admin template if you need to. To override an admin template, copy it into your templates directory keeping the same relative path and filename. Django's administration site will use your custom template instead of the default one.

Finally, let's add a link to each Order object in the list display page of the administration site. Edit the admin.py file of the orders application and add the following code to it, above the OrderAdmin class:

from django.urls import reverse
from django.utils.safestring import mark_safe

def order_detail(obj):
return mark_safe('<a href="{}">View</a>'.format(
reverse('orders:admin_order_detail', args=[obj.id])))

This is a function that takes an Order object as an argument and returns an HTML link for the admin_order_detail URL. Django escapes HTML output by default. We have to use the mark_safe function to avoid auto-escaping.

Use the mark_safe function to avoid HTML-escaping. When you use mark_safe, make sure to escape input that has come from the user to avoid cross-site scripting.

Then, edit the OrderAdmin class to display the link:

class OrderAdmin(admin.ModelAdmin): 
list_display = ['id',
'first_name',
# ...
'updated',
order_detail]

Open http://127.0.0.1:8000/admin/orders/order/ in your browser. Each row now includes a View link as follows:

Click on the View link for any order to load the custom order detail page. You should see a page like the following one:

..................Content has been hidden....................

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