Hello!

django + django-cms 开发实战-APP开发

2013-03-04  |  django django-cms python 

上一篇做了基础工作,完成了django与django-cms的安装与配置,繁琐的是它们那些依赖也要一项一项的去了解,不会有一键安装这种好事。今天这一篇将创建我的第一个APP。他是一个简单的产品管理与展示系统。let's go!

模型

python manage.py startapp products

在已有的Project中使用这个命令可以自动创建一个默认的APP(一个python模块)。他包括四个默认文件。我的APP需要数据库支持,所以首先要在models.py中设计数据库结构。django提供了非常方便的数据库对象化方案。具体的类如下:

import os
from datetime import date
from django.db import models
from filebrowser.fields import FileBrowseField

# 每个类代表一张表,类的属性指代表的字段
class Categroy(models.Model):
    # name用于后台显示,title用于前端页面显示
    name = models.CharField(max_length = 100)
    title = models.CharField(max_length = 100)
    order = models.IntegerField(default = 0)
    # 用户可以自定义路径,及此分类下的模板
    path = models.CharField(max_length = 20, blank=False)
    list_template = models.CharField(max_length = 200, blank = False, default = "products/list.html")
    item_template = models.CharField(max_length = 200, blank = False, default = "products/item.html")
    keywords = models.CharField(max_length = 300, blank = False)
    descoription  = models.TextField(blank = False)
    display = models.BooleanField(default = True)
    add_time = models.DateTimeField(auto_now_add = True)
    # 支持无限分类, 注意与自己做一对一关系时,第一个参数使用字符型的self,不能直接用变量,因为它指代的是实例
    parent = models.ForeignKey('self', blank = True, null = True)
    # 使用一个递归来计算当前分类的层级
    def _count_level(self):
        def loop_count_level(parent, level = 2):
            if parent.parent:
                return loop_count_level(parent.parent, level + 1)
            else:
                return level
        if self.parent == None:
            return 1
        else:
            return loop_count_level(self.parent)
    # 可以自定义一些方法做一些计算,同时用property把它变成实例的属性
    level = property(_count_level)
    def _children(self):
        # 使用 ‘__’ 双下划线可以指代关联表中的字段
        return Categroy.objects.filter(parent__id = self.id)
    children = property(_children)
    def _products(self):
        return Product.objects.filter(categroy = self)
    products = property(_products)
    def _all_products(self):
        cates = [self] + [c for c in self.children]
        # 使用 ‘__’ 双下划线还可以做一些简单的字段查询
        return Product.objects.filter(categroy__in = cates)
    all_products = property(_all_products)
    # 在没有明确指明时,实例可以返回的字符串信息
    def __unicode__(self):
        return "%s %s" % ("-" * self.level, self.name)

class Product(models.Model):
    ....

安装APP

创建完表字段后,我们有两步要做,一是把APP安装到django中:

INSTALLED_APPS = (
    ...
    'products',
    ...
)

二是要使用命令在数据库中生成真正的表:

python manage.py syncdb --all

在admin中管理

django的admin后台为程序员节省了很多时间,它可以快速为你自己的APP搭建一个后台。我们需要在APP中创建一个admin.py文件,在其中把我们的数据模型注册到admin中,代码如下:

from django.contrib import admin
from news.models import Categroy, Products

admin.site.register(Categroy)
admin.site.register(Products)

再次登录后台会发现已经可以看到Categroy和Products的管理条目了,基本的删查改都提供。这时还有个问题,文本编辑器(tinyMCE)没有出现,接下来要对admin.py做一些定制工作:

# 继承ModelForm类可以控制admin后台中编辑form中的项
class ProductForm(forms.ModelForm):
    content = forms.CharField(widget=TinyMCE(attrs={'cols': '90', 'rows': '60'}))
    class Meta:
        model = Product

class ProductAdmin(admin.ModelAdmin):
    form = ProductForm

admin.site.register(Categroy)
admin.site.register(Product, ProductAdmin)

相当于覆盖了默认的表单内容。django还提供了很多功能让用户可以方便的定制后台。

页面展示

页面展示需要考虑两个问题:通过什么样的URL访问;如何展示内容。django通过 urls.py 来设置访问的url,views.py 则包括所有的视图代码。 其实我们project创建时已经有了一个urls.py,把需要访问的url都设置在此处也没有问题,但为了减少耦合,尽量把app自己的url规则配置在自己的urls.py中。只需要在project中的urls.py中设置如下代码,即可把访问串联起来:

url(r'^products/', include("product.urls")) # 注意正则中并没有出现"$"结束符

每一个url正则对应一个view, 可以多个url正则对应一个view。没有命名的正则表达式组,按顺序对应view的参数,而命名的正则表达式组对应view参数的名称。

(r'^(?P<id>[0-9]+)/?$', views.product) # product方法中的参数id 可以获取url中匹配到的id

views中用作返回视图的方法,总能接收一个'request'参数,而它本身必须返回一个 HttpResponse对象

def product(request, id=""):
    try:
        id = int(id)
        product = Product.objects.get(id = id)
    except Product.DoesNotExist:
        return Http404
    # render_to_response能快速的返回HttpResponse对象
    return render_to_response(product.categroy.item_template,
                              {"product":product}, context_instance=RequestContext(request)) 
    # context_instance 上下文实例可以让你在模板中访问一些常规的变量,
    # 比如,当前用户这样的信息,不需要你自己往 dictionary 加入这些内容。

模板

模板的内容相对简单,前端对这些比较熟悉。