书籍出处:https://www.packtpub.com/web-development/django-example
原作者:Antonio Melé

译者@ucag注:咳咳,第七章终于来了。其实在一月份就翻译完了????但是后来我回老家了,就没发出来。各位久等了~)

译者@夜夜月注:真羡慕有寒假和暑假的人- -愿你们的寒暑假作业越多越好,粗略的校对了下,精校版本请大家继续等待)

第七章

建立一个在线商店

在上一章,你创建了一个用户跟踪系统和建立了一个用户活跃流。你也学习了 Django 信号是如何工作的,并且把 Redis 融合进了项目中来为图像视图计数。在这一章中,你将学会如何建立一个最基本的在线商店。你将会为你的产品创建目录和使用 Django sessions 实现一个购物车。你也将学习怎样定制上下文处理器( context processors )以及用 Celery 来激活动态任务。

在这一章中,你将学会:

  • 创建一个产品目录

  • 使用 Django sessions 建立购物车

  • 管理顾客的订单

  • 用 Celery 发送异步通知

创建一个在线商店项目(project)

我们将从新建一个在线商店项目开始。我们的用户可以浏览产品目录并且可以向购物车中添加商品。最后,他们将清点购物车然后下单。这一章涵盖了在线商店的以下几个功能:

  • 创建产品目录模型(模型),将它们添加到管理站点,创建基本的视图(view)来展示目录

  • 使用 Django sessions 建立一个购物车系统,使用户可以在浏览网站的过程中保存他们选中的商品

  • 创建下单表单和功能

  • 发送一封异步的确认邮件在用户下单的时候

首先,用以下命令来为你的新项目创建一个虚拟环境,然后激活它:

mkdir env
virtualenv env/myshop
source env/myshop/bin/activate

用以下命令在你的虚拟环境中安装 Django :

pip install django==1.8.6

创建一个叫做 myshop 的新项目,再创建一个叫做 shop 的应用,命令如下:

django-admin startproject myshopcd myshop
django-admin startapp shop

编辑你项目中的 settings.py 文件,像下面这样将你的应用添加到 INSTALLED_APPS 中:

INSTALLED_APPS = [    # ...
    'shop',
]

现在你的应用已经在项目中激活。接下来让我们为产品目录定义模型(models)。

创建产品目录模型(models)

我们商店中的目录将会由不同分类的产品组成。每一个产品会有一个名字,一段可选的描述,一张可选的图片,价格,以及库存。 编辑位于shop应用中的models.py文件,添加以下代码:

from django.db import modelsclass Category(models.Model):
     name = models.CharField(max_length=200,
                                  db_index=True)
     slug = models.SlugField(max_length=200,
                            db_index=True,
                                   unique=True)     class Meta:
          ordering = ('name',)
          verbose_name = 'category'
          verbose_name_plural = 'categories'
 
    def __str__(self):
        return self.name        
class Product(models.Model):
    category = models.ForeignKey(Category, 
                                 related_name='products')
    name = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField(max_length=200, db_index=True)
    image = models.ImageField(upload_to='products/%Y/%m/%d',
                              blank=True)
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.PositiveIntegerField()
    available = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)    class Meta:
        ordering = ('name',)
        index_together = (('id', 'slug'),)    def __str__(self):
        return self.name

这是我们的 Category 和 Product 模型(models)。Category 模型(models)由一个 name 字段和一个唯一的 slug字段构成。Product 模型(model):

  • category: 这是一个链接向 Category 的 ForeignKey 。这是个多对一(many-to-one)关系。一个产品可以属于一个分类,一个分类也可包含多个产品。

  • name: 这是产品的名字

  • slug: 用来为这个产品建立 URL 的 slug

  • image: 可选的产品图片

  • description: 可选的产品描述

  • price: 这是个 DecimalField译者@ucag注:十进制字段)。这个字段使用 Python 的 decimal.Decimal 元类来保存一个固定精度的十进制数。max_digits 属性可用于设定数字的最大值, decimal_places 属性用于设置小数位数。

  • stock: 这是个 PositiveIntegerField译者@ucag注:正整数字段) 来保存这个产品的库存。

  • available: 这个布尔值用于展示产品是否可供购买。这使得我们可在目录中使产品废弃或生效。

  • created: 当对象被创建时这个字段被保存。

  • update: 当对象最后一次被更新时这个字段被保存。

对于 price 字段,我们使用 DecimalField 而不是 FloatField 来避免精度问题。

我们总是使用 DecimalField 来保存货币值。 FloatField 在内部使用 Python 的 float 类型。反之, DecimalField使用的是 Python 中的 Decimal 类型,使用 Decimal 类型可以避免精度问题。

在 Product 模型(model)中的 Meta 类中,我们使用 index_together 元选项来指定 id 和 slug 字段的共同索引。我们定义这个索引,因为我们准备使用这两个字段来查询产品,两个字段被索引在一起来提高使用双字段查询的效率。

由于我们会在模型(models)中和图片打交道,打开 shell ,用下面的命令安装 Pillow :

pip isntall Pillow==2.9.0

现在,运行下面的命令来为你的项目创建初始迁移:

python manage.py makemigrations

你将会看到以下输出:

Migrations for 'shop':
    0001_initial.py:
      - Create model Category
      - Create model Product
      - Alter index_together for product (1 constraint(s))

用下面的命令来同步你的数据库:

python mange.py migrate

你将会看到包含下面这一行的输出:

 Applying shop.0001_initial... OK

现在数据库已经和你的模型(models)同步了。

注册目录模型(models)到管理站点

让我们把模型(models)注册到管理站点,这样我们就可以轻松管理产品和产品分类了。编辑 shop 应用的 admin.py 文件,添加如下代码:

from django.contrib import adminfrom .models import Category, Productclass CategoryAdmin(admin.ModelAdmin):
    list_display = ['name', 'slug']
    prepopulated_fields = {'slug': ('name',)}
admin.site.register(Category, CategoryAdmin)class ProductAdmin(admin.ModelAdmin):
    list_display = ['name', 'slug', 'price', 'stock', 
                    'available', 'created', 'updated']
    list_filter = ['available', 'created', 'updated']
    list_editable = ['price', 'stock', 'available']
    prepopulated_fields = {'slug': ('name',)}
admin.site.register(Product, ProductAdmin)

记住,我们使用 prepopulated_fields 属性来指定那些要使用其他字段来自动赋值的字段。正如你以前看到的那样,这样做可以很方便的生成 slugs 。我们在 ProductAdmin 类中使用 list_editable 属性来设置可被编辑的字段,并且这些字段都在管理站点的列表页被列出。这样可以让你一次编辑多行。任何在 list_editable 的字段也必须在 list_display 中,因为只有这样被展示的字段才可以被编辑。

现在,使用如下命令为你的站点创建一个超级用户:

python manage.py createsuperuser

使用命令 python manage.py runserver 启动开发服务器。 访问 http://127.0.0.1:8000/admin/shop/product/add ,登录你刚才创建的超级用户。在管理站点的交互界面添加一个新的品种和产品。 product 的更改页面如下所示:

创建目录视图(views)

为了展示产品目录, 我们需要创建一个视图(view)来列出所有产品或者是给出的筛选后的产品。编辑 shop 应用中的 views.py文件,添加如下代码:

from django.shortcuts import render, get_object_or_404from .models import Category, Productdef product_list(request, category_slug=None):
    category = None
    categories = Category.objects.all()
    products = Product.objects.filter(available=True)    if category_slug:
        category = get_object_or_404(Category, slug=category_slug)
        products = products.filter(category=category)    return render(request, 
                  'shop/product/list.html', 
                  {'category': category,                  'categories': categories,                  'products': products})

我们只筛选 available=True 的查询集来检索可用的产品。我们使用一个可选参数 category_slug 通过所给产品类别来有选择性的筛选产品。

我们也需要一个视图来检索和展示单一的产品。把下面的代码添加进去:

def product_detail(request, id, slug):
    product = get_object_or_404(Product, 
                                id=id, 
                                slug=slug, 
                                available=True)    return render(request, 
                  'shop/product/detail.html', 
                  {'product': product})

product_detail 视图(view)接收 id 和 slug 参数来检索 Product 实例。我们可以只用 ID 就可以得到这个实例,因为它是一个独一无二的属性。尽管,我们在 URL 中引入了 slug 来建立搜索引擎友好(SEO-friendly)的 URL。

在创建了产品列表和明细视图(views)之后,我们该为它们定义 URL 模式了。在 shop 应用的路径下创建一个新的文件,命名为 urls.py ,然后添加如下代码:

from django.conf.urls import urlfrom . import views

urlpatterns = [
    url(r'^$', views.product_list, name='product_list'),
    url(r'^(?P<category_slug>[-\w]+)/$', 
        views.product_list, 
        name='product_list_by_category'),
    url(r'^(?P<id>\d+)/(?P<slug>[-\w]+)/$', 
        views.product_detail, 
        name='product_detail'),

这些是我们产品目录的URL模式。 我们为 product_list 视图(view)定义了两个不同的 URL 模式。 命名为product_list 的模式不带参数调用 product_list 视图(view);命名为 product_list_bu_category 的模式向视图(view)函数传递一个 category_slug 参数,以便通过给定的产品种类来筛选产品。我们为 product_detail 视图(view)添加的模式传递了 id 和 slug 参数来检索特定的产品。

像这样编辑 myshop 项目中的 urls.py 文件:

from django.conf.urls import url, includefrom django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^', include('shop.urls', namespace='shop')),
    ]

在项目的主要 URL 模式中,我们引入了 shop 应用的 URL 模式,并指定了一个命名空间,叫做 shop

现在,编辑 shop 应用中的 models.py 文件,导入 reverse() 函数,然后给 Category 模型和 Product 模型添加 get_absolute_url() 方法:

from django.core.urlresolvers import reverse# ...class Category(models.Model):
    # ...
    def get_absolute_url(self):
        return reverse('shop:product_list_by_category',
                        args=[self.slug])                        
class Product(models.Model):# ...
    def get_absolute_url(self):
        return reverse('shop:product_detail',
            args=[self.id, self.slug])

正如你已经知道的那样, get_absolute_url() 是检索一个对象的 URL 约定俗成的方法。这里,我们将使用我们刚刚在 urls.py文件中定义的 URL 模式。

创建目录模板(templates)

现在,我们需要为产品列表和明细视图创建模板(templates)。在 shop 应用的路径下创建如下路径和文件:

templates/
    shop/
        base.html
        product/            list.html
            detail.html

我们需要定义一个基础模板(template),然后在产品列表和明细模板(templates)中继承它。 编辑 shop/base.html 模板(template),添加如下代码:

{% load static %}<!DOCTYPE html><html><head>
    <meta charset="utf-8" />
    <title>{% block title %}My shop{% endblock %}</title>
    <link href="{% static "css/base.css" %}" rel="stylesheet"></head><body>
    <div id="header">
        <a href="/" class="logo">My shop</a>
    </div>
    <div id="subheader">
        <div class="cart">
            Your cart is empty.        </div>
    </div>
    <div id="content">
        {% block content %}
        {% endblock %}    </div></body></html>

这就是我们将为我们的商店应用使用的基础模板(template)。为了引入模板使用的 CSS 和图像,你需要复制这一章示例代码中的静态文件,位于 shop 应用中的 static/ 路径下。把它们复制到你的项目中相同的地方。

编辑 shop/product/list.html 模板(template),然后添加如下代码:

{% extends "shop/base.html" %}
{% load static %}

{% block title %}
    {% if category %}{{ category.name }}{% else %}Products{% endif %}
{% endblock %}

{% block content %}    <div id="sidebar">
        <h3>Categories</h3>
        <ul>
            <li {% if not category %}class="selected"{% endif %}>
                <a href="{% url "shop:product_list" %}">All</a>
            </li>
        {% for c in categories %}            <li {% if category.slug == c.slug %}class="selected"{% endif %}>
                <a href="{{ c.get_absolute_url }}">{{ c.name }}</a>
            </li>
http://www.cnblogs.com/levelksk/p/6495402.html

网友评论