ตัวอย่างใช้งาน Redis ร่วมกับ Werkzeug
Werkzeug เป็น WSGI ของ python
หากยังไม่ได้ติดตั้ง Werkzeug ต้องทำการติดตั้งก่อน โดยโหลด Werkzeug
(โหลดที่นี่)
ทำการติดตั้งด้วย easy_install เหมือน redis
>> C:\Python27\Scripts> easy_install Werkzeug
อ้างอิง :: Werkzeug Tutorial
ตัวอย่างจะเป็นการทำ url ของเว็บให้สั้นลงอย่างง่าย โดยใช้ redis และ werkzeug ให้มีการเพิ่มการบันทึกลงฐานข้อมูลและแสดงผลจากฐานข้อมูลออกไปโดย
1. สร้างโฟล์เดอร์ที่จำเป็นสำหรับการส้ราง shortly นี้ ตามตัวอย่างคือ
- 2014-09-29_2-13-11.jpg (7.11 KiB) Viewed 2949 times
นี่เป็นเพียง Folder ที่ใช้เพื่อเก็บ Code และ Template เท่านั้น
ตัวอย่างไฟล์ html ที่สร้างไว้ใน template
- 2014-09-29_10-19-20.jpg (11.58 KiB) Viewed 2949 times
2. ต่อไปเป็นการสร้างไฟล์ จะใช้ชื่อว่า shortly.py เก็บไว้ในโฟล์เดอร์ โดยทำการ import ตัว function หรือ method ที่จำเป็น
[code]import os
import redis
import urlparse
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, NotFound
from werkzeug.wsgi import SharedDataMiddleware
from werkzeug.utils import redirect
from jinja2 import Environment, FileSystemLoader[/code]
3. สร้างฟังก์ชั่นสำหรับการเรียกใช้งาน
ฟังก์ชั่นสำหรับสร้างไอดีให้แก่ URLโค้ด: เลือกทั้งหมด
def base36_encode(number):
assert number >= 0, 'positive integer required'
if number == 0:
return '0'
base36 = []
while number != 0:
number, i = divmod(number, 36)
base36.append('0123456789abcdefghijklmnopqrstuvwxyz'[i])
return ''.join(reversed(base36))
- 2014-09-29_2-31-09.jpg (44.37 KiB) Viewed 2949 times
ฟังก์ชั่นสำหรับกำหนดว่า URL ที่ใส่ ก่อนทำให้เป็น Shortly นั้น ต้องมี 'http' หรือ 'https' โค้ด: เลือกทั้งหมด
def is_valid_url(url):
parts = urlparse.urlparse(url)
return parts.scheme in ('http', 'https')
- 2014-09-29_2-34-03.jpg (34.99 KiB) Viewed 2949 times
- 2014-09-29_2-34-15.jpg (40.47 KiB) Viewed 2949 times
ฟังก์ชั่นรับและส่งค่า URLโค้ด: เลือกทั้งหมด
def get_hostname(url):
return urlparse.urlparse(url).netloc
คลาสสำหรับการเชื่อมต่อฐานข้อมูล Redisโค้ด: เลือกทั้งหมด
class Shortly(object):
def __init__(self, config):
self.redis = redis.Redis(config['redis_host'], config['redis_port'])
template_path = os.path.join(os.path.dirname(__file__), 'templates')
"""ระบุตำแหน่งที่ไฟล์ Template อยู่ """
self.jinja_env = Environment(loader=FileSystemLoader(template_path),
autoescape=True)
self.jinja_env.filters['hostname'] = get_hostname
"""กำหนดเส้นทางที่จะทำการเรียก Template ที่ต้องการ"""
self.url_map = Map([
Rule('/', endpoint='new_url'),
Rule('/<short_id>', endpoint='follow_short_link'),
Rule('/<short_id>+', endpoint='short_link_details')
])
- 2014-09-26_16-08-13.jpg (97.7 KiB) Viewed 2949 times
ฟังก์ชั่นสำหรับการตรวจสอบ URL ว่าใส่ถูกต้องหรือไม่ โค้ด: เลือกทั้งหมด
def on_new_url(self, request):
error = None
url = ''
if request.method == 'POST':
url = request.form['url']
if not is_valid_url(url):
error = 'Please enter a valid URL'
else:
short_id = self.insert_url(url)
return redirect('/%s+' % short_id)
return self.render_template('new_url.html', error=error, url=url)
ฟังก์ชั่นสำหรับนับจำนวนครั้งในการกดเข้าไปที่ Shortly URL
โค้ด: เลือกทั้งหมด
def on_follow_short_link(self, request, short_id):
link_target = self.redis.get('url-target:' + short_id)
if link_target is None:
raise NotFound()
self.redis.incr('click-count:' + short_id)
return redirect(link_target)
def on_short_link_details(self, request, short_id):
link_target = self.redis.get('url-target:' + short_id)
if link_target is None:
raise NotFound()
click_count = int(self.redis.get('click-count:' + short_id) or 0)
return self.render_template('short_link_details.html',
link_target=link_target,
short_id=short_id,
click_count=click_count
)
- 2014-09-26_16-08-57.jpg (82.83 KiB) Viewed 2949 times
ฟังก์ชั่นเรียกหน้า templates เมื่อใส่ URL ที่ไม่ถูกต้อง จะแสดง ERROR 404 ขึ้นมา โค้ด: เลือกทั้งหมด
def error_404(self):
response = self.render_template('404.html')
response.status_code = 404
return response
ฟังก์ชัน insert ค่าลงฐานข้อมูล Redis โค้ด: เลือกทั้งหมด
def insert_url(self, url):
short_id = self.redis.get('reverse-url:' + url)
if short_id is not None:
return short_id
url_num = self.redis.incr('last-url-id')
short_id = base36_encode(url_num)
self.redis.set('url-target:' + short_id, url)
self.redis.set('reverse-url:' + url, short_id)
return short_id
โค้ด: เลือกทั้งหมด
def render_template(self, template_name, **context):
t = self.jinja_env.get_template(template_name)
return Response(t.render(context), mimetype='text/html')
คืนค่า Response โค้ด: เลือกทั้งหมด
def dispatch_request(self, request):
adapter = self.url_map.bind_to_environ(request.environ)
try:
endpoint, values = adapter.match()
return getattr(self, 'on_' + endpoint)(request, **values)
except NotFound, e:
return self.error_404()
except HTTPException, e:
return e
รับ Request โค้ด: เลือกทั้งหมด
def wsgi_app(self, environ, start_response):
request = Request(environ)
response = self.dispatch_request(request)
return response(environ, start_response)
ฟังก์ชันพิเศษไว้สำหรับใช้งาน start_response จาก Class โค้ด: เลือกทั้งหมด
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
ฟังก์ชันทำหน้าที่เรียกใช้ Classโค้ด: เลือกทั้งหมด
def create_app(redis_host='localhost', redis_port=6379, with_static=True):
app = Shortly({
'redis_host': redis_host,
'redis_port': redis_port
})
if with_static: """เรียกใช้ไฟล์ CSS ที่ในโฟลเดอร์ Static"""
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
'/static': os.path.join(os.path.dirname(__file__), 'static')
})
return app
การเรียกใช้งาน Appilication โดยรันขึ้น Server และให้มีการรีโหลดอัตโนมัติ
โค้ด: เลือกทั้งหมด
if __name__ == '__main__':
from werkzeug.serving import run_simple
app = create_app()
run_simple('127.0.0.1', 5009, app, use_debugger=True, use_reloader=True)
- 2014-09-29_10-23-42.jpg (25.5 KiB) Viewed 2949 times
- 2014-09-26_16-07-45.jpg (79.63 KiB) Viewed 2949 times
* Redis สามารถทำให้เชื่อมต่อกับฐานข้อมูลทั้ง MySQL และ PostgreSQL ได้อีกด้วย
ขอให้สนุกกับการนำ Redis ไปประยุกต์ใช้นะคะ