创建产品目录模型(models)
image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True)
由于我们会在模型(models)中和图片打交道,打开 shell ,用下面的命令安装 Pillow :
pip isntall Pillow==2.9.0
因为使用ImageField来保存产品图片,需要开发服务器来服务上传图片文件。编辑myshop项目的settings.py文件,添加以下设置:
MEDIA_URL ='/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media/')
MEDIA_URL是基础 URL:它为用户上传的媒体文件提供服务。
MEDIA_ROOT是一个本地路径:媒体文件就在这个路径下,并且是由我们动态的将BASE_DIR添加到它的前面而得到的。
为了让 Django 给通过开发服务器上传的媒体文件提供服务,编辑myshop中的urls.py文件,添加如下代码:
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
记住,我们仅仅在开发中像这样提供静态文件服务。在生产环境下,你不应该用 Django 来服务静态文件。
class Meta:
ordering = ('name',)
index_together = (('id','slug'),)
index_together元选项来指定id和slug字段的共同索引。我们定义这个索引,因为我们准备使用这两个字段来查询产品,两个字段被索引在一起来提高使用双字段查询的效率。
class CategoryAdmin(admin.ModelAdmin):
list_display = ['name', 'slug']
prepopulated_fields = {'slug': ('name',)}
使用 prepopulated_fields 属性来指定那些要使用其他字段来自动赋值的字段。
购物车实现
使用 Django 的会话框架(seesion framework)来保存购物车。在购物车最终被完成或用户下单之前,购物车将会保存在会话中。我们需要为购物车和购物车里的商品创建额外的 Django 模型(models)。
会话中间件使当前会话在request对象中可用。你可以用request.seesion连接当前会话,它的使用方式和 Python 的字典相似。会话字典接收任何默认的可被序列化为 JSON 的 Python 对象。
现在,你需要把购物车和会话关联起来。购物车像下面这样工作:
1.当需要一个购物车时,我们检查顾客是否已经设置了一个会话键( session key)。如果会话中没有购物车,我们就创建一个新的购物车,然后把它保存在购物车的会话键中。
2.对于连续的请求,我们在会话键中执行相同的检查和获取购物车内物品的操作。我们在会话中检索购物车的物品和他们在数据库中相关联的Product对象。
上下文处理器----(模版标签?)
上下文处理器是一个接收request对象为参数并返回一个已经添加了请求上下文字典的 Python 函数。他们在你需要让什么东西在所有模板都可用时迟早会派上用场。
例:from .cart import Cart
def cart(request):
return{'cart': Cart(request)}
如你所见,一个上下文处理器是一个函数,这个函数接收一个request对象作为参数,然后返回一个对象字典,这些对象可用于所有使用RequestContext渲染的模板。在我们的上下文处理器中,我们使用request对象实例化了购物车,然后让它作为一个名为cart的参数对模板可用。
创建订单模型
一个模型用来保存订单的详细信息,第二个模型用来保存购买的物品,包括物品的价格和数量。
Redis配置
1.进入到redis目录下:cd~/java/redis-3.2.5
2.运行make命令:make
执行完后,redis已经成功下载到了本地,第一次运行make命令,命令可能会不存在,会自动弹出安装的一个窗口,点击确定安装即可
3.输入src/redis-server启动redis服务:src/redis-server
如果把服务停掉,再重新输入src/redis-server启动服务时,会报Redis Creating Server TCP listening socket *:6379: unable to bind socket的错误,是因为启动时没指定redis.conf文件,这个文件在解析后的redis-3.2.5文件夹下,进入到redis-3.2.5文件夹下,输入如下命令就可以启动服务了:src/redis-serverredis.conf
在src目录下,有个内置的客户端工作redis-cli,输入src/redis-cli命令打开客户端
cd java/redis-3.2.5/
src/redis-cli
ping
set foo bar
get foo
以上ping命令返回PONG,说明服务已经可以正常使用,并通过set命令,设置了foo变量的值是bar
使用Redis实现一个简单的推荐系统
1. settings.py(和 Redis 服务器建立连接)
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_DB = 1
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令(比如,SET命令对应与StrictRedis.set方法)。Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。 简单说,官方推荐使用StrictRedis方法。
r = redis.StrictRedis(host=settings.REDIS_HOST,
port=settings.REDIS_PORT,
db=settings.REDIS_DB)
1. 得到所给 `Product` 对象的产品 ID
2. 迭代所有的产品 ID。对于每个 "id" ,我们迭代所有的产品 ID 并且跳过所有相同的产品,这样我们就可以得到和每个产品一起购买的产品。
3. 我们使用 "get_product_id()" 方法来获取 Redis 产品键。对于一个 ID 为 33 的产品,这个方法返回键 `product:33:purchased_with` 。这个键用于包含和这个产品被一同购买的产品 ID 的有序集。
4. 我们把有序集中的每个产品 "id" 的评分加一。评分表示另一个产品和所给产品一起购买的次数。
1. 得到所给 "Product" 对象的 ID
2. 如果只有一个产品,我们就检索一同购买的产品的 ID,并按照他们的购买时间来排序。这样做,我们就可以使用 Redis 的 "ZRANGE"命令。我们通过 "max_results"属性来限制结果的数量。
3. 如果有多于一个的产品被给予,我们就生成一个临时的和产品 ID 一同创建的 Redis 键。
4. 我们把包含在每个所给产品的有序集中东西的评分组合并相加,我们使用 Redis 的 "ZUNIONSTORE"命令来实现这个操作。"ZUNIONSTORE"命令执行了对有序集的所给键的求和,然后在新的 Redis 键中保存每个元素的求和。你可以在这里阅读更多关于这个命令的信息:http://redisio/commands/ZUNIONSTORE 。我们在临时键中保存分数的求和。
5. 因为我们已经求和了评分,我们或许会获取我们推荐的重复商品。我们就使用 "ZREM"命令来把他们从生成的有序集中删除。
6. 我们从临时键中检索产品 ID,使用 "ZREM"命令来按照他们的评分排序。我们把结果的数量限制在"max_results"属性指定的值内。然后我们删除了临时键。
7. 最后,我们用所给的 `id` 获取 `Product` 对象,并且按照同样的顺序来排序。
1.Redis Zincrby :Redis Zincrby 命令对有序集合中指定成员的分数加上增量 increment
2.Redis Zrange:Redis Zrange 返回有序集中,指定区间内的成员。其中成员的位置按分数值递增(从小到大)来排序。具有相同分数值的成员按字典序(lexicographical order )来排列。
如果你需要成员按值递减(从大到小)来排列,请使用ZREVRANGE命令。
下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
3.Redis Zunionstore:命令计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。
默认情况下,结果集中某个成员的分数值是所有给定集下该成员分数值之和 。
Redis Zrem:命令用于移除有序集中的一个或多个成员,不存在的成员将被忽略。
当 key 存在但不是有序集类型时,返回一个错误。
注意:在 Redis 2.4 版本以前, ZREM 每次只能删除一个元素。
Celery的使用
Celery是Python开发的分布式任务调度模块,Celery本身不含消息服务,它使用第三方消息服务来传递任务,目前,Celery支持的消息服务有RabbitMQ、Redis甚至是数据库,当然Redis应该是最佳选择。
指定消息队列(发送和接受消息的传输者):
celery = Celery('tasks', broker='redis://localhost:6379/0')
celery = Celery('hello',broker='amqp://guest@localhost//')
Celery 用消息通信,通常使用中间人(Broker)在客户端和职程间斡旋。这个过程从客户端向队列添加消息开始,之后中间人把消息派送给进程。
Celery 是一个分发队列,它可以处理大量的信息。它既可以执行实时操作也支持任务调度。使用 Celery 不仅可以让你很轻松的创建异步任务还可以让这些任务尽快执行,但是你需要在一个指定的时间调度他们执行。
安装 Celery
让我们安装 Celery 然后把它整合进你的项目中。用下面的命令安装 Celery:
pip install celery==3.1.18
Celery 需要一个消息代理(message broker)来管理请求。这个代理负责向 Celery 的 worker 发送消息,当接收到消息时 worker 就会执行任务。让我们安装一个消息代理。
有几个 Celery 的消息代理可供选择,包括键值对储存,比如 Redis 或者是实时消息系统,比如 RabbitMQ。我们会用 RabbitMQ 配置 Celery ,因为它是 Celery 推荐的 message worker。
安装 RabbitMQ
RabbitMQ 是默认的中间人,所以除了需要你要使用的中间人实例的 URL 位置, 它并不需要任何额外的依赖或起始配置:
BROKER_URL='amqp://guest:guest@localhost:5672//'
如果你用的是 Linux,你可以用下面这个命令安装 RabbitMQ :
apt-get install rabbitmg
如果你需要在 Mac OSX 或者 Windows 上安装 RabbitMQ,你可以在这个网站找到独立的支持版本:
https://www.rabbitmq.com/download.html
在安装它之后,使用下面的命令执行 RabbitMQ
rabbitmg-server
步骤一:创建celery.py
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'picha.settings')
app = Celery('picha')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
步骤二:引入celery应用
为了确保在django启动时加载了celery应用,在settings.py旁边新建__init__.py,并添加以下代码到__init__.py中。
from__future__importabsolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from.celery import appascelery_app
打开另外一个 shell ,使用以下命令开启 celery worker :
celery -A myshop worker -l info
发送任务
sendmail.delay(...)
监控 Celery
你或许想要监控执行了的异步任务。下面就是一个基于 web 的监控 Celery 的工具。你可以用下面的命令安装 Flower:
pip install flower
celery -A myshop flower