python 提升生活和办公效率

Django学习--无状态的Web应用

2019-03-01  本文已影响0人  alue

这两天看了轻量级Django的前三章, 收获很多, 对于Django学习很有帮助. 这里利用书中第二章的例子,继续扩展最简单的Django应用, 完成一个占位图片服务器.
占位图片经常被用于应用程序原型搭建. 典型的占位图片服务器会接收一个指定大小的url, 并生成该图片. url可以携带其他信息, 本例子中只包含宽高.对服务器的所有的请求信息, 都包含在url中, 无需权限验证, 是一个很好的无状态应用示例.
该项目涉及的知识点有:

  1. url
    • 利用(?P<name>pattern)方法设计url
  2. 设计视图---生成特定尺寸的图片
    • 用form验证尺寸
    • 用pil生成图片
  3. 优化性能
    • 后端缓存
    • etag前端缓存
  4. 静态文件
    • 配置参数 INSTALLED_APPS TEMPLATES STATICFILES_DIRS STATIC_URL
    • 添加html模版和css

设计url

from django.conf.urls import url
urlpatterns = (
    url(r'^image/(?P<width>[0-9]+)x(?P<height>[0-9]+)/$', placeholder, name='placeholder'),
    url(r'^$', index, name='homepage'),
)

设计视图+优化性能(前后端缓存)

#---------------  视图模块   ---------------------#
from django.http import HttpResponse, HttpResponseBadRequest
from django import forms
from io import BytesIO
from PIL import Image, ImageDraw
from django.core.cache import cache

class ImageForm(forms.Form):
    height = forms.IntegerField(min_value=1, max_value=2000)
    width = forms.IntegerField(min_value=1, max_value=2000)

    def generate(self, image_format='PNG'):
        height = self.cleaned_data['height']
        width = self.cleaned_data['width']
        # 服务器缓存(后端): 先看是否已有缓存
        key = f'{width}.{height}.{image_format}'
        content = cache.get(key)
        if content is None:
            image = Image.new('RGB', (width, height))
            draw = ImageDraw.Draw(image)
            text = f'{width}x{height}'
            textwidth, textheight = draw.textsize(text)
            if textwidth < width and textheight < height:
                texttop = (height - textheight) // 2
                textleft = (width - textwidth) // 2
                draw.text((textleft, texttop), text, fill=(255, 255, 255))
            content = BytesIO()
            image.save(content, image_format)
            content.seek(0)
            #   加入缓存
            cache.set(key,content,60 * 60)
        return content

# 浏览器缓存(前端): etag 可以利用浏览器缓存技术
import hashlib
def generate_etag(request,width,height):
    content = f'Placeholder:{width} x {height}'
    return hashlib.sha1(content.encode('utf-8')).hexdigest()

from django.views.decorators.http import etag
@etag(generate_etag)
def placeholder(request, width, height):
    # 传给视图的参数都是字符串,可以利用表单验证
    form = ImageForm({'height': height, 'width': width})
    if form.is_valid():
        height = form.cleaned_data['height']
        width = form.cleaned_data['width']
        # 生成特定尺寸的图片
        image = form.generate()
        return HttpResponse(image, content_type='image/png')
    else:
        return HttpResponseBadRequest('Invalid Image Request')

#  主页视图
from django.shortcuts import reverse,render
def index(request):
    example = reverse('placeholder',kwargs={'width':50,'height':50})
    context = {
        'example':request.build_absolute_uri(example)
    }
    return render(request,'home.html',context)

配置参数

#---------------  参数配置   ---------------------#
import os, sys
from django.conf import settings

DEBUG = os.environ.get('DEBUG', 'on') == 'on'
SECRET_KEY = os.environ.get('SECRET_KEY', 'tu#z*sc)@7+%!s75-*ao(wje0^r0e%sw15t)$92dl*yn+_uh!(')
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')
BASE_DIR = os.path.dirname(__file__)

settings.configure(
    DEBUG=DEBUG,
    SECRET_KEY=SECRET_KEY,
    ALLOWED_HOSTS=ALLOWED_HOSTS,
    ROOT_URLCONF=__name__,
    INSTALLED_APPS=(
       'django.contrib.staticfiles',
    ),
    TEMPLATES = (
        {
            'BACKEND':'django.template.backends.django.DjangoTemplates',
            'DIRS':(os.path.join(BASE_DIR,'templates'),),
        },
    ),
    STATICFILES_DIRS=(
        os.path.join(BASE_DIR,'static'),
    ),
    STATIC_URL = '/static/',
)

静态文件

将上述三段代码合并为一个placeholder.py文件, 并在同级目录下新建两个文件templates/home.htmlstatic/cite.css, 分别用于存放模板和样式. 这两个文件可以如下设计:

<!-- templates/home.html -->
{% load staticfiles %}
<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Django 占位图片</title>
    <link rel="stylesheet" href="{% static 'site.css' %}" type="text/css">
</head>

<body>
<h1>Django 占位图片</h1>
<p>{% lorem %}</p>
<p>用类似下面链接,访问占位图片:</p>
<pre>
    &lt; img src="{{example}}" &gt;
</pre>
<h2>示例</h2>
<ul>
    <li><img src="{% url 'placeholder' width=50 height=50 %}" alt="图片1"></li>
    <li><img src="{% url 'placeholder' width=100 height=50 %}" alt="图片2"></li>
    <li><img src="{% url 'placeholder' width=50 height=100 %}" alt="图片3"></li>
</ul>
</body>
</html>
//static/cite.css
body{
    text-align: center;
}

ul{
    list-style: none;
}
li{
    display: inline-block;
}

结果展示

这样在命令行运行python placeholder.py runserver, 打开http://localhost:8000/, 即可看到下面的结果:

运行结果

书中这个非常简短的例子, 综合应用了很多django框架知识, 值得认真学习总结. 下一篇, 将学习如何利用Django实现快速原型开发.

上一篇下一篇

猜你喜欢

热点阅读