返回介绍

第六章- 模型管理

发布于 2025-02-26 23:49:05 字数 11106 浏览 0 评论 0 收藏 0

本章我们覆盖以下议题:

Customizing columns in the change list page
Creating admin actions
Developing change list filters
Exchanging administration settings for external apps
Inserting a map into a change form

引言

The Django framework comes with a built-in administration system for your models. With very little effort, you can set up filterable, searchable, and sortable lists for browsing your models, and configure forms for adding and editing data. In this chapter, we will go through advanced techniques to customize administration by developing some practical cases.

Django 框架为你的模型提供了一个内建的管理系统。只需少许努力你就可以为模型浏览配置一个可过滤的,可搜索的,可排序的列表,以及配置可以添加和编辑数据的表单。在这一章,我们会通过编写一个实际的例子来彻底了解定制管理所需的高级技术。

定制切换列表页面的中的列

Change list views in the default Django administration system let you have an overview of all instances of specific models. By default, the model admin property, list_display , controls which fields to show in different columns. But additionally, you can have custom functions set there that return data from relations or display custom HTML. In this recipe, we will create a special function for the list_display property that shows an image in one of the columns of the list view. As a bonus, we will make one field editable directly in the list view by adding the list_editable setting.

改变默认的 Django 管理系统中的列表试图能够让你拥有一个特定模型的全部实例的概览。默认,模型 admin 的特性 list_display 控制着在不同的列中哪一个字段会被显示。此外,你可以定制函数

开始前的准备

To start with, make sure that django.contrib.admin is in INSTALLED_APPS in the settings, and AdminSite is hooked into the URL configuration. Then, create a new app named products and put it under INSTALLED_APPS . This app will have the Product and ProductPhoto models, where one product might have multiple photos. For this example, we will also be using UrlMixin, which was defined in the Creating a model mixin with URL-related methods recipe in Chapter 2, Database Structure.

要准备开始的话,请确保 django.contrib.admin 在设置文件的 INSTALLED_APPS 中,而且 Admin 站点已经挂在 URL 配置中了。然后创建一个新的名称为 products 的应用并把它放到 INSTALLED_APPS 中去。该应用拥有模型 ProdcutProdcutPhoto ,这里一个 procut 可能拥有多张照片。就我们的这个例子而言,我们也会用到 UrlMixin,

Let's create the Product and ProductPhoto models in the models.py file as follows:

如下,我们在 models.py 文件中模型 Prodcut 和 ProdcutPhoto:

#products/models.py
# -*- coding: UTF-8 -*-
import os
from django.db import models
from django.utils.timezone import now as timezone_now
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.core.urlresolvers import NoReverseMatch
from utils.models import UrlMixin

def upload_to(instance, filename):
  now = timezone_now()
  filename_base, filename_ext = os.path.splitext(filename)
  return "products/%s/%s%s" % (
    instance.product.slug,
    now.strftime("%Y%m%d%H%M%S"),
    filename_ext.lower(),
  )

class Product(UrlMixin):
  title = models.CharField(_("title"), max_length=200)
  slug = models.SlugField(_("slug"), max_length=200)
  description = models.TextField(_("description"), blank=True)
  price = models.DecimalField(_(u"price (€)"), max_digits=8,
    decimal_places=2, blank=True, null=True)

  class Meta:
    verbose_name = _("Product")
    verbose_name_plural = _("Products")

  def __unicode__(self):
    return self.title

  def get_url_path(self):
    try:
      return reverse("product_detail", kwargs={
        "slug": self.slug})
    except NoReverseMatch:
      return ""

class ProductPhoto(models.Model):
  product = models.ForeignKey(Product)
  photo = models.ImageField(_("photo"), upload_to=upload_to)

  class Meta:
    verbose_name = _("Photo")
    verbose_name_plural = _("Photos")

  def __unicode__(self):
    return self.photo.name

具体做法

We will create a simple administration for the Product model that will have instances of the ProductPhoto model attached to the product as inlines.

In the list_display property, we will define the get_photo method name of the model admin that will be used to show the first photo from the many-to-one relationship.

Let's create an admin.py file with the following content:

#products/admin.py
# -*- coding: UTF-8 -*-
from django.db import models
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponse

from products.models import Product, ProductPhoto

class ProductPhotoInline(admin.StackedInline):
  model = ProductPhoto
  extra = 0

class ProductAdmin(admin.ModelAdmin):
  list_display = ["title", "get_photo", "price"]
  list_editable = ["price"]

  fieldsets = (
    (_("Product"), {
      "fields": ("title", "slug", "description", "price"),
    }),
  )
  prepopulated_fields = {"slug": ("title",)}
  inlines = [ProductPhotoInline]

  def get_photo(self, obj):
    project_photos = obj.productphoto_set.all()[:1]
    if project_photos.count() > 0:
      return u"""<a href="%(product_url)s" target="_blank">
        <img src="%(photo_url)s" alt="" width="100" />
      </a>""" % {
        "product_url": obj.get_url_path(),
        "photo_url":  project_photos[0].photo.url,
      }
    return u""

  get_photo.short_description = _("First photo")
  get_photo.allow_tags = True

admin.site.register(Product, ProductAdmin)

工作原理

If you look at the product administration list in the browser, it will look like this:

图片:略

Besides the normal field names, the list_display property accepts a function or another callable, the name of an attribute of the admin model, or the name of the attribute of the model. Each callable will be passed a model instance as the first argument. So, in our example, we have the get_photo method of the model admin that retrieves Product as obj. The method tries to get the first ProductPhoto from the many-to-one relation and, if it exists, it returns HTML with the

The short_description property of the callable defines the title shown for the column. The allow_tags property tells the administration not to escape the HTML values.

In addition, the price field is made editable by the list_editable setting and there is a save button at the bottom to save the whole list of products.

参阅

  • The Creating a model mixin with URL-related methods recipe in Chapter 2, Database Structure
  • The Creating admin actions recipe
  • The Developing change list filters recipe

添加 Admin 的行为

The Django administration system provides actions that we can execute for selected items in the list. There is one action given by default, and it is used to delete selected instances. In this recipe, we will create an additional action for the list of the Product model that allows administrators to export selected products to Excel spreadsheets.

开始前的准备

我们就从之前方法中所创建的应用 products 开始。

具体做法

Admin actions are functions that take three arguments: the current ModelAdmin value, the current HttpRequest value, and the QuerySet value containing the selected items. Perform the following steps:

Let's create an export_xls function in the admin.py file of the products app, as follows:

#products/admin.py
# -*- coding: UTF-8 -*-
import xlwt
# ... other imports ...

def export_xls(modeladmin, request, queryset):
  response = HttpResponse(mimetype="application/ms-excel")
  response["Content-Disposition"] = "attachment; "\
    "filename=products.xls"
  wb = xlwt.Workbook(encoding="utf-8")
  ws = wb.add_sheet("Products")

  row_num = 0
  ### Print Title Row ###  
  columns = [
    # column name, column width
    (u"ID", 2000),
    (u"Title", 6000),
    (u"Description", 8000),
    (u"Price (€)", 3000),
  ]

  header_style = xlwt.XFStyle()
  header_style.font.bold = True

  for col_num in xrange(len(columns)):
    ws.write(row_num, col_num, columns[col_num][0],
      header_style)
    # set column width
    ws.col(col_num).width = columns[col_num][1]

  ### Print Content ###

  text_style = xlwt.XFStyle()
  text_style.alignment.wrap = 1

  price_style = xlwt.XFStyle()
  price_style.num_format_str = "0.00"

  styles = [text_style, text_style, text_style, price_style] 
  for obj in queryset.order_by("pk"):
    row_num += 1
    row = [
      obj.pk,
      obj.title,
      obj.description,
      obj.price,
    ]
    for col_num in xrange(len(row)):
      ws.write(row_num, col_num, row[col_num],
        styles[col_num])

  wb.save(response)
  return response

export_xls.short_description = u"Export XLS”
  1. Then, add the actions setting to ProductAdmin, as follows:
class ProductAdmin(admin.ModelAdmin):
  # ...
  actions = [export_xls]

工作原理

If you look at the product administration list page in the browser, you will see a new action called Export XLS along with the default action Delete selected Products:

图片:略

By default, admin actions do something with QuerySet and redirect the administrator back to the change list page. However, for some more complex actions like this, HttpResponse can be returned. The export_xls function returns HttpResponse with the MIME type of Excel spreadsheet. Using the Content-Disposition header, we set the response to be downloadable with the file named products.xls.

Then, we use the xlwt Python module to create the Excel file.

At first, the workbook with UTF-8 encoding is created. Then, we add a sheet named Products to it. We will be using the write method of the sheet to set the content and style for each cell and the col method to retrieve the column and set the width to it.

To have an overview of all columns in the sheet, we create a list of tuples with column names and widths. Excel uses some magical units for the widths of the columns. They are 1/256 of the width of the zero character for the default font. Next, we define the header style to be bold.

As we have the columns defined, we loop through them and fill the first row with the column names, also assigning the bold style to them.

Then, we create a style for normal cells and for the prices. The text in normal cells will be wrapped in multiple lines. Prices will have a special number style with two points after the decimal point.

Lastly, we go through the QuerySet of the selected products ordered by ID and print the specified fields into corresponding cells, also applying specific styles.

The workbook is saved to the file-like HttpResponse object and the resulting Excel sheet looks like this:

表格:略

参阅

  • Chapter 9, Data Import and Export
  • The Customizing columns in the change list page recipe
  • The Developing change list filters recipe

开发

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文