(二)無狀態的web應用(單py的Django佔位圖片服務器)

本文爲做者原創,轉載請註明出處(http://www.cnblogs.com/mar-q/)by 負贔屓css

 

   閱讀本文建議瞭解Django框架的基本工做流程,瞭解WSGI應用,若是對以上不是很清楚,建議結合《Lightweight Django》(中文爲《輕量級Django》)進行閱讀。本文結合該書實現了一個佔位圖片服務器,對深刻理解Django框架使用流程,瞭解無狀態web應用有必定幫助。
  這裏的狀態是指是客戶端和服務器之間會話的狀態(例如寫入權限、讀取權限、驗證身份等等),HTTP自己是一個無狀態協議,而Django這樣的框架使用cookie、session等等會話機制,把同一個客戶端發送的請求進行了特定的狀態綁定。 可是這樣存在的問題比較多,好比分佈式服務器架構的請求在這種一致性狀態下的讀取和寫入衝突。因此無狀態的應用沒必要在服務器維持一致的狀態,而是根據請求來進行操做,易於擴展、緩存和負載均衡。URL能夠傳輸大多數狀態,採起可複用應用和可組合服務兩種方式。這裏經過圖片佔位服務器爲例進行一個實現:
 
1、什麼是佔位圖片服務器
  佔位圖片服務器就是指,服務器接收URL傳遞的圖片大小、顏色等信息,並生成圖片,通常不須要權限驗證,所以是一個很好的無狀態應用候選。 
 
2、建立項目(Django版本1.11.3
  經過自建模板進行建立,若是看不懂這裏建議先閱讀第一篇http://www.cnblogs.com/mar-q/p/7841972.html:
django-admin.py startproject placeholder --template=template
  
   一、修改URL匹配模式:增長參數width和height
urlpatterns=[
    url(u'^$',index, name='homepage'),
    url(u'^image/(?P<width>[0-9]+)x(?P<height>[0-9]+)/$', placeholder, name='placeholder'),
]
 
   二、對setting進行配置,這裏咱們須要建立一個簡單的展現界面,有一個html和對應的css,須要對它們進路徑配置。須要注意的是當前的目錄結構,setting中的BASE_DIR爲相對路徑,將BASE_DIR與templates和static目錄結合便可獲得相應的html和css路徑。
DEBUG = os.environ.get('DEBUG','on')=='on'
SECRET_KEY = os.environ.get('SECRET_KEY', '&8x8ono))lhdi_6fg!h_9uv3l97w$m$(m6lg&0tttyb2e_lnlv')
ALLOWED_HOSTS=['*']
BASE_DIR = os.path.dirname(__file__)
settings.configure(
    DEBUG=DEBUG,
    SECRET_KEY=SECRET_KEY,
    ROOT_URLCONF=__name__,
    ALLOWED_HOSTS=ALLOWED_HOSTS,
    MIDDLEWARE=[
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ],
    INSTALLED_APPS=[
        'django.contrib.staticfiles',
    ],
    TEMPLATES=[
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            # 'APP_DIRS': True,
        }
    ],
    STATICFILES_DIRS=[
        os.path.join(BASE_DIR, 'static'),
    ],
    STATIC_URL = '/static/'
) 
 
  三、建立一個Image的生成類: 
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_formate='PNG'):
        height = self.cleaned_data['height']
        width = self.cleaned_data['width']
        key = '{}.{}.{}'.format(width, height, image_formate)
        content = cache.get(key) ##增長服務器緩存
        if content is None:
            image = Image.new('RGB', (width, height))
            draw = ImageDraw.Draw(image)
            text = '{}x{}'.format(width, 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_formate)
            content.seek(0)
            cache.set(key, content, 60*60)
        return content

   這個ImageForm類是一個表單類,用於接收URL傳遞過來的圖片寬高信息,定義了generate方法,用於生成對應尺寸的佔位圖片,同時增長了cache緩存的設置,檢測到對應尺寸的content先從緩存獲取(Django默認使用本地過程、內存緩存)。html

  四、建立視圖函數placeholder和index:
def generate_etag(req, width, height):
    content = 'Placeholder: {0}x{1}'.format(width, height)
    return hashlib.sha1(content.encode('utf-8')).hexdigest()
@etag(generate_etag)
def placeholder(req, width, height):
    form = ImageForm({'width':width, 'height':height})
    if form.is_valid():
        image = form.generate()
        return HttpResponse(image, content_type='image/png')
    else:
        return HttpResponseBadRequest('圖片格式錯誤’)
def index(req):
    example = reverse('placeholder', kwargs={'width':50, 'height':50})##經過url標籤和參數獲取地址
    context = {
        'example': req.build_absolute_uri(example)##把上面造成的地址傳遞給頁面
    }
    return render_to_response('home.html', context)
   注意這裏使用了etag修飾符,這裏使用它的主要目的是經過客戶端瀏覽器進行緩存,這裏定義了一個generate_etag的函數,它接收placeholder視圖函數的參數,並經過hashlib創建一個基於傳入的weigh和height變化的加密值,這個值就是etag值,客戶端第一次訪問服務器時會向服務器發送佔位圖片請求,服務器生成並返回圖片以及這個etag值,客戶端會將其在緩存內配對緩存,當下一次再進行一樣參數的訪問時,它將會收到304 Not Modified的返回值,瀏覽器會使用自身的緩存。如圖所示: 
 
   五、爲主頁視圖建立template和static文件(html及css)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Place Holder</title>
    {% load staticfiles %}
    <link rel="stylesheet" href="{% static 'site.css' %} " type="text/css">
</head>
<body>
    <h1>Django Placeholder Images</h1>
    <p>該服務應用的功能是提供圖片佔位符</p>
    <p>請求服務器響應須要提供圖片的width和height參數<b>/image/&lt;width&gt;x&lt;height&gt;/</b></p>
    <pre> &lt; img src="{{ example }}" &gt;</pre>
    <h2>Example</h2>
    <ul>
        <li><img src="{% url 'placeholder' width=50 height=50 %}"></li>
        <li><img src="{% url 'placeholder' width=100 height=50 %}"></li>
        <li><img src="{% url 'placeholder' width=50 height=100 %}"></li>
    </ul>
</body>
</html>
   Html中咱們定義了5段文字,其中第4段調用了index函數中對應的example參數,這個參數中保存的是一個示例的url地址構造方式,在index中咱們能夠看到使用了reverse和req.build_absolute_uri,此時會返回一個完整的連接地址。
body{
    text-align: center;
}
ul{
    list-style: none;font-size:50px
}
li{
    display: inline-block;
}
 
   六、最後咱們添加wsgi服務,並在main函數中寫入調用入口:
application = get_wsgi_application()
if __name__ == "__main__":
    from django.core.management import execute_from_command_line
    execute_from_command_line(sys.argv)
 
3、運行並顯示效果: 
python templateHello.py runserver 0.0.0.0:8000
##或者  gunicorn -w 4 -b 0.0.0.0:8000 hello --log-file=-

  完整代碼能夠參考https://github.com/helloworld77/DjangoPrimer.git。不多在上面放項目,基本都是看別人的代碼,水平有限,還請見諒。
相關文章
相關標籤/搜索