Customizing Admin

Satchmo does not make extensive modifications to the default Django admin. However, it is relatively straightforward to make changes to the admin for your needs - without modifying Satchmo’s core.

Modifying the Product Model

The default Product admin model displays all possible fields and makes some assumptions about what you would like to see. If you would like to modify the admin to use special widgets or change fields that are displayed, use admin.site.unregister to unregister the current product model and add your own.

Assuming you have a localapp admin.py file, use code similar to the example below:

from django.contrib import admin
from django.db import models
from product.models import Product
from product.admin import ProductOptions
from tinymce.widgets import AdminTinyMCE


"""
Rest of your admin models go here.
"""

admin.site.unregister(Product)

class CustomProductAdmin(ProductOptions):
    formfield_overrides = {
        models.TextField: {'widget': AdminTinyMCE},
        }
    list_display = ('name', 'unit_price', 'items_in_stock', 'active','featured')
    list_display_links = ('name',)

admin.site.register(Product, CustomProductAdmin)

This code does a couple of things:

  • Replace the default Text Editor widget with TinyMCE widget
  • Changes the columns in the list_display to be a subset of the default
  • Ensures that the name is a link to the product

Note

These changes must be included in an application that is listed after all the other Satchmo Apps in INSTALLED_APPS

Using Mix-ins to customize the admin

Mix-ins are a very powerful feature available in python that allow for advanced customization of Satchmo. With mix-ins you can add arbitrary elements (functions, model attributes, etc...) to any class/model. The full uses of mix-ins are outside the scope of this document but let’s start with an example.

Suppose you want to show product SKUs of all the products in an order on the Product Orders page. The screenshot below shows you what the current order screen looks like:

_images/order-screen2.png

We will modify it to show all the skus in an order like this:

_images/order-screen1.png

Here is a chunk of code that would create a list of skus for a given order:

def order_sku(self):
    allsku = ''
    for item in self.orderitem_set.all():
        allsku += "%s<br />" % item.product.sku
    return allsku
order_sku.allow_tags = True
order_sku.short_description = "Order SKUs"

You could then add ‘order_sku’ to the list display of Order. The problem is, where do you put the chunk of code listed above? You could add it to the Order models but that would be forking Satchmo and later when it was time to upgrade to the next version of Satchmo things could be much more difficult. The solution is mix-ins.

Mix-ins allow you to dynamically change the inheritance of a class. We will change Orders from looking like this:

class Order(models.Model):

to this:

class Order(models.Model, ourNewClass):

In order to accomplish this without actually modifying existing Satchmo done, you can put order_sku in a class:

class OrderExtend:
    def order_sku(self):
        allsku = ''
        for item in self.orderitem_set.all():
            allsku += "%s<br />" % item.product.sku
        return allsku
    order_sku.allow_tags = True
    order_sku.short_description = "Order SKUs"

and adding:

Order.__bases__ += (OrderExtend,)

The last bit takes the __bases__ of Order (which are its base inheritance classes) and adds OrderExtend to it. Because Order now inherits from OrderExtend we can use order_sku. To make skus show up in the admin we create localsite/admin.py and put all of our code in it so it looks like this:

from django.contrib import admin
from django.db import models
from satchmo_store.shop.models import Order, OrderItem
from satchmo_store.shop.admin import OrderOptions

class OrderExtend:
    def order_sku(self):
        allsku = ''
        for item in self.orderitem_set.all():
            allsku += "%s<br />" % item.product.sku
        return allsku
    order_sku.allow_tags = True
    order_sku.short_description = "Order SKUs"

Order.__bases__ += (OrderExtend,)

admin.site.unregister(Order)

class CustomOrderAdmin(OrderOptions):
    list_display = ('id', 'order_sku', 'contact', 'time_stamp',
                    'order_total', 'balance_forward', 'status',
                    'invoice', 'packingslip','shippinglabel')

admin.site.register(Order, CustomOrderAdmin)

Obviously you could do a lot more with mix-ins. You can add arbitray functions and attributes to any model and any class. A much longer explaination that is not django specific but has more examples (and the document used as a reference for writing this up) can be found here