第十章 附加功能.md

最后更新于:2022-04-01 22:00:01

在本章,我们将学习以下技巧: * 使用Django Shell * The monkey patching slugification function * The monkey patching model administration * Toggling Debug Toolbar * Using ThreadLocalMiddleware * Caching the method value * 通过电子邮件获取错误报告详情 * 使用 mod_wsgi 在Apache上部署项目 * 创建并使用Farbic部署脚本 ## 引言 In this chapter, we will go through several other important bits and pieces that will help you understand and utilize Django even better. You will get an overview of how to use the Django shell to experiment with the code before writing it into files. You will be introduced to monkey patching, also known as guerrilla patching, which is a powerful feature of dynamical languages such as Python, but should be used with moderation. You will learn how to debug your code and check its performance. Lastly, you will be taught how to deploy your Django project on a dedicated server. ## 使用Django shell With the virtual environment activated and your project directory selected as the current directory, enter this command into your command-line tool: ```python (myproject_env)$ python manage shell ``` By executing the preceding command, you get into an interactive Python shell configured for your Django project, where you can play around with the code and inspect classes, try out methods, or execute scripts on the fly. In this recipe, we will go through the most important functions you need to know to work with the Django shell. ## 准备开始 Optionally, you can install IPython or bpython using one of the following commands, which will highlight the syntax for the output of your Django shell: ```python (myproject_env)$ pip install ipython (myproject_env)$ pip install bpython ``` ## 具体实现过程 你可以通过下面的这些说明学习到Django shell的使用基础: 1. 输入下面的命令以运行Django shell: ```python (myproject_env)$ python manage shell ``` The prompt will change to In [1]: or >>> depending on whether you use IPython or not. Now you can import classes, functions, or variables and play around with them. For example, to see the version of an installed module, you can import the module and then try to read its __version__, VERSION, or version variables: ```python >>> import MySQLdb >>> MySQLdb.__version__ '1.2.3' ``` To get a comprehensive description of a module, class, function, method, keyword, or documentation topic, use the help function. You can either pass a string with the path to a specific entity, or the entity itself, as follows: ```python >>> help('django.forms') ``` This will open the help page for the django.forms module. Use the arrow keys to scroll the page up and down. Press Q to get back to the shell. This is an example of passing an entity to the help function. This will open a help page for the ModelForm class: ```python >>> from django.forms import ModelForm >>> help(ModelForm) ``` To quickly see what fields and values are available for a model instance, use the __dict__ attribute. Also use the pprint function to get dictionaries printed in a more readable format (not just one long line): ```python >>> from pprint import pprint >>> from django.contrib.contenttypes.models import ContentType >>> pprint(ContentType.objects.all()[0].__dict__) {'_state': , 'app_label': u'bulletin_board', 'id': 11, 'model': u'bulletin', 'name': u'Bulletin'} ``` Note that by using this method, we don't get many-to-many relationships. But this might be enough for a quick overview of the fields and values. To get all the available properties and methods of an object, you can use the dir function, as follows: ```python >>> dir(ContentType()) ['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', u'__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', '__weakref__', '_base_manager', '_default_manager', '_deferred', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 'app_label', 'clean', 'clean_fields', 'content_type_set_for_comment', 'date_error_message', 'delete', 'full_clean', 'get_all_objects_for_this_type', 'get_object_for_this_type', 'id', 'logentry_set', 'model', 'model_class', 'name', 'natural_key', 'objects', 'permis‘ ’sion_set', 'pk', 'prepare_database_save', 'save', 'save_base', 'serializable_value', 'unique_error_message', 'validate_unique'] ``` The Django shell is useful for experimenting with QuerySets or regular expressions before putting them into your model methods, views, or management commands. For example, to check the e-mail-validation regular expression, you can type this into the Django shell: ```python >>> import re >>> email_pattern = re.compile(r'[^@]+@[^@]+\.[^@]+') >>> email_pattern.match('aidas@bendoraitis.lt') <_sre.SRE_Match object at 0x1075681d0> ``` To exit the Django shell, press Ctrl + D or type the following command: >>> exit() ## 工作原理 The difference between a normal Python shell and the Django shell is that when you run the Django shell, manage.py sets the DJANGO_SETTINGS_MODULE environment variable to the project's settings path, and then Django gets set up. So, all database queries, templates, URL configuration, or anything else are handled within the context of your project. ## 参见 *The The monkey patching slugification function recipe* *The The monkey patching model administration recipe* ## The monkey patching slugification function *Monkey patching or guerrilla patching* is a piece of code that extends or modifies another piece of code at runtime. It is not recommended to use monkey patching often, but sometimes it is the only possible way to fix a bug in third-party modules without creating a separate branch of the module, or to prepare unit tests for testing without using complex database manipulations. In this recipe, you will learn how to exchange the default slugify function with the third-party awesome-slugify module, which handles German, Greek, and Russian words smarter and also allows custom slugification for other languages. The slugify function is used to create a URL-friendly version of the object's title or the uploaded filename: it strips the leading and trailing whitespace, converts the text to lowercase, removes nonword characters, and converts spaces to hyphens.
';

第九章 数据的导入与导出.md

最后更新于:2022-04-01 21:59:59

本章,我们会学习以下技巧: * 从一个本地CSV文件导入数据 * 从一个本地Excel文件导入数据 * 从一个外部JSON文件导入数据 * 从一个外部XML文件导入数据 * 生成一个可过滤的RSS订阅 * 使用Tastypie为第三方提供数据
';

第八章 层次化结构.md

最后更新于:2022-04-01 21:59:57

本章-我们会学习以下内容: * 创建分层类别 * 用django-mptt-admin生成分类admin接口 * 用django-mptt-tree创建分类admin接口 * 在模板中传递分类 * 在表单中使用一个单选字段选择一个分类 * 在表单中使用一个复选框列表选择多个分类
';

第七章 Django CMS.md

最后更新于:2022-04-01 21:59:54

本章我们会学习以下内容: ``` Creating templates for Django CMS 为Django CMS创建模板 Structuring the page menu 组织页面菜单 Converting an app to a CMS app 把一个应用转换到CMS应用 Attaching your own navigation 加入用户自己的导航 Writing your own CMS plugin 编写用户自己的CMS插件 Adding new fields to the CMS page 对CMS页面添加新字段
';

第六章 模型管理.md

最后更新于:2022-04-01 21:59:52

# 第六章- 模型管理 ******************* 本章我们覆盖以下议题: 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`中去。该应用拥有模型`Prodcut`和`ProdcutPhoto`,这里一个procut可能拥有多张照片。就我们的这个例子而言,我们也会用到UrlMixin, Let's create the Product and ProductPhoto models in the models.py file as follows: 如下,我们在models.py文件中模型Prodcut和ProdcutPhoto: ```python #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: ```python #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""" """ % { "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 tag linked to the detail page of Product. 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: ```python #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” ``` 2. Then, add the actions setting to ProductAdmin, as follows: ```python 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 ## 开发
';

第五章 定制模板过滤器与标签.md

最后更新于:2022-04-01 21:59:50

{% raw %} 第五章 定制模板过滤器和标签 ------------------------ 本章,我们会学习以下内容: * 遵循模板过滤器和标签的约定 * 创建一个模板过滤器显示已经过去的天数 * 创建一个模板过滤器提取第一个媒体对象 * 创建一个模板过滤器使URL可读 * 创建一个模板标签在模板中载入一个QuerySet * 创建一个模板标签为模板解析内容 * 创建一个模板标签修改request查询参数 ## 简介 如你所知,Django有一个非常庞大的模板系统,特别是模板继承, ## 遵循模板过滤器和标签的约定 Custom template filters and tags can become a total mess if you don't have persistent guidelines to follow. Template filters and tags should serve template editors as much as possible. They should be both handy and flexible. In this recipe, we will look at some conventions that should be used when enhancing the functionality of the Django template system. 滤器和标签时会让你完全不知所措。模板过滤器和标签应该尽可能的服务于模板编辑器,而且它们都应该同时具有操作方便和灵活扩展的特性。在这个做法中,我们会见到一些在增强Django模板系统功能时所用到的几点约定。 ### 如何做 扩张Django模板系统时遵循以下约定: 1. 当在视图,上下文处理器,或者模型方法中,页面更适合逻辑时,不要创建或者使用定制模板过滤器、标签。你的页面是上下文指定时,比如一个对象列表或者一个详细对象视图,载入视图中的对象。如果你需要在每一个页面都显示某些内容,可以创建一个上下文管理器。当你需要获取一个没有关联到模板上下文的对象的某些特性时,要用模型的定制方法而不是使用模板过滤器。 2. 使用 _tags后缀命名模板标签库。当你的app命名不同于模板标签库时,你可以避免模糊的包导入问题。 3. 例如,通过使用如下注释,在最后创建的库中,从标签中分离过滤器: # -*- coding: UTF-8 -*- from django import template register = template.Library() ### FILTERS ### # .. your filters go here .. ### TAGS ### # .. your tags go here.. 4. 通过下面的格式,创建的模板标签就可以被轻松记住: for [app_name.model_name]:使用该格式以使用指定的模型 using [template_name]:使用该格式将一个模板的模板标签输出 limit [count]:使用该格式将结果限制为一个指定的数量 as [context_variable]:使用该结构可以将结构保存到一个在之后多次使用的上下文变量 5. 要尽量避免在模板标签中按位置地定义多个值除非它们都是不解自明的。否则,这会有可能使开发者迷惑。 6. 尽可能的使用更多的可理解的参数。没有引号的字符串应该当作需要解析的上下文变量或者可以提醒你关于模板标签组件的短语。 ## 参见 The Creating a template filter to show how many days have passed recipe The Creating a template filter to extract the first media object recipe The Creating a template filter to humanize URLs recipe The Creating a template tag to include a template if it exists recipe The Creating a template tag to load a QuerySet in a template recipe The Creating a template tag to parse content as a template recipe The Creating a template tag to modify request query parameters recipe” ## 创建一个模板过滤器显示已经过去的天数 Not all people keep track of the date, and when talking about creation or modification dates of cutting-edge information, for many of us, it is more convenient to read the time difference, for example, the blog entry was posted three days ago, the news article was published today, and the user last logged in yesterday. In this recipe, we will create a template filter named days_since that converts dates to humanized time differences. 不是所有的人都持续关注时间,而且在谈论最新日期信息的新建和修改时,对于我们大多数人来说读取时间差是更为合适的一种选择,例如,博客内容在发布于三天之前,新的文章在今天发布了,而用户则是在昨天进行了最后的登陆行为。在这个做法中,我们将新一个称作days_since的可以转换日期到人类可读时间差的模板过滤器。 ## 准备开始 Create the utils app and put it under `INSTALLED_APPS` in the settings, if you haven't done that yet. Then, create a Python package named templatetags inside this app (Python packages are directories with an empty ` __init__.py` file). 创建utils应用并将它放到settings文件中的`INSTALLED_APPS`下,要是你还没有按照我说的去做的话。然后,在这个应用里边创建一个名叫templatetags的Python文件夹(Python包是一个拥有内容为空的`__init__.py`文件)。 ## 我该怎么做 使用下面的内容创建一个utility_tags.py文件: ```python #utils/templatetags/utility_tags.py # -*- coding: UTF-8 -*- from datetime import datetime from django import template from django.utils.translation import ugettext_lazy as _ from django.utils.timezone import now as tz_now register = template.Library() ### FILTERS ### @register.filter def days_since(value): """ Returns number of days between today and value.""" today = tz_now().date() if isinstance(value, datetime.datetime): value = value.date() diff = today - value if diff.days > 1: return _("%s days ago") % diff.days elif diff.days == 1: return _("yesterday") elif diff.days == 0: return _("today") else: # Date is in the future; return formatted date. return value.strftime("%B %d, %Y") ``` ## 工作原理 If you use this filter in a template like the following, it will render something like yesterday or 5 days ago: 假如你在模板中使用了如下所示的过滤器,那么该过滤器会将日期渲染为比如,今天,或者五天前: ```python “{% load utility_tags %} {{ object.created|days_since }} You can apply this filter to the values of the date and datetime types. ``` Each template-tag library has a register where filters and tags are collected. Django filters are functions registered by the `register.filter` decorator. By default, the filter in the template system will be named the same as the function or the other callable object. If you want, you can set a different name for the filter by passing name to the decorator, as follows: 每个模板标签库都有一个收集过滤器和标签的注册器。Django过滤器是通过装饰器`register.filter`注册过的函数。默认,模板系统中的过滤器的名称和函数或者其他可调用对象的名称相同。如下,如果你有需要的话,你可以通过传递名称到装饰器来为过滤器设置一个不同的名称: ```python @register.filter(name="humanized_days_since") def days_since(value): ... ``` The filter itself is quite self-explanatory. At first, the current date is read. If the given value of the filter is of the datetime type, the date is extracted. Then, the difference between today and the extracted value is calculated. Depending on the number of days, different string results are returned. ## 还有更多 This filter is easy to extend to also show the difference in time, such as just now, 7 minutes ago, or 3 hours ago. Just operate the datetime values instead of the date values. ## 参阅 The Creating a template filter to extract the first media object recipe The Creating a template filter to humanize URLs recipe ## 创建一个模板过滤器以提取第一个媒体对象 Imagine that you are developing a blog overview page, and for each post, you want to show images, music, or videos in that page taken from the content. In such a case, you need to extract the ``, ``, and `` tags out of the HTML content of the post. In this recipe, we will see how to do this using regular expressions in the `get_first_media` filter. ## 准备开始吧 We will start with the `utils` app that should be set in `INSTALLED_APPS `in the settings and the `templatetags` package inside this app. ## 如何做 In the `utility_tags.py` file, add the following content: 在`utility_tags.py`文件中,添加以下内容: ```python #utils/templatetags/utility_tags.py # -*- coding: UTF-8 -*- import re from django import template from django.utils.safestring import mark_safe register = template.Library() ### FILTERS ### media_file_regex = re.compile(r"|" r"<(img|embed) [^>]+>") ) @register.filter def get_first_media(content): """ Returns the first image or flash file from the html content """ m = media_file_regex.search(content) media_tag = "" if m: media_tag = m.group() return mark_safe(media_tag) ``` ## 工作原理 While the HTML content in the database is valid, when you put the following code in the template, it will retrieve the ``, ``, or `` tags from the content field of the object, or an empty string if no media is found there: ```python {% load utility_tags %} {{ object.content|get_first_media }} ``` At first, we define the compiled regular expression as `media_file_regex`, then in the filter, we perform a search for that regular expression pattern. By default, the result will show the <, >, and & symbols escaped as `<`, `>`, and `&`; entities. But we use the `mark_safe` function that marks the result as safe HTML ready to be shown in the template without escaping. ## 还有更多 It is very easy to extend this filter to also extract the `|" r"