台中.py

Django Tutorial v.s. Flask Tutorial

Keith Yang

Django Tutorial
v.s. Flask Tutorial


Keith Yang

Photos of me

yang.keitheis.org

biideal, Taipei.py, PyCon APAC


@keitheis

大綱

  1. 介紹 Python web frameworks
  2. pip 安裝套件與 virtualenv 設定
  3. Project 的結構
  4. 網址:Routing and Views: Django urls v.s. Flask app.url
  5. 網頁樣版:Django template v.s. Jinja2
  6. 表單與驗證:Django Form v.s. Flask-WTF (WTForms)
  7. 資料庫物件:Django ORM v.s. Flask-SQLAlchemy
  8. 使用者登入:Django User v.s. Flask-Login
  9. 第三方套件與在台灣的學習資源

這個字色
是屬於 Django 的

這個字色
是屬於 Flask 的

介紹 Python web frameworks

隨隨便便就一打

每個人都可以寫
/用自己喜歡的框架

如何挑選

如何挑選(續)

pip 安裝套件與 virtualenv 設定

安裝 pip

用 pip 安裝 virtualenv

pip install

Django Flask Flask-WTF Flask-SQLAlchemy

Project 的結構

Django 1.6.5
(taipy)% django-admin.py startproject mysite
(taipy)% tree mysite/
    mysite/
    - manage.py
    - mysite/
        - __init__.py
        - settings.py
        - urls.py
        - wsgi.py
 
    1 directory, 5 files
Flask 0.10.1
(taipy)% mkdir myleaf
(taipy)% cat > myleaf/leaf.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello Leaf!"

if __name__ == "__main__":
    app.run()

執行 Run server

Flask
(taipy)% cd myleaf
(taipy)% python leaf.py
    * Running on http://127.0.0.1:5000/
 
Django
(taipy)% cd ../mysite
(taipy)% python manage.py runserver
    ...
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CONTROL-C.

小型 Flask 應用架構

- myleaf/
    - templates/
    - static/
    - main/
        - __init__.py
        - errors.py
        - forms.py
        - views.py
    - __init__.py
    - tests/
        - __init__.py
        - test*.py
    - email.py
    - models.py
    - requirements.txt
    - config.py

中大型 Flask 應用架構

- myleaf/
    - app/
        - templates/
        - static/
        - main/...
        - __init__.py
        - email.py
        - models.py
    - migrations/...
    - tests/...
    - venv/...
    - manage.py
    - requirements.txt
    - config.py

模組化
的概念

Django Apps

> Django Project 是由一個個的 Django APP 所組成, 對於剛學習 Django 的人來說,可能會不知道所謂的 Django APP 是什麼。 其實一個 Django APP 很簡單,一般來說我們會希望一個 Django APP 能夠 " do one thing and do it well." 也就是說盡可能的讓功能單純, 這樣子日後更能夠有 reuse 的機會。- Andy Dai
(taipy)% python manage.py startapp excuse
(taipy)% tree mysite/
    mysite/
    - excuse/
        - __init__.py
        - admin.py
        - models.py
        - tests.py
        - views.py
    - manage.py
    - mysite/...
 
    3 directory, 13 files

Flask Apps?

Flask Blueprint!

Flask Blueprint

from flask import current_app, Blueprint, render_template
admin = Blueprint('admin', __name__, url_prefix='/admin')

@admin.route('/')
def index():
    return render_template(current_app.config['INDEX_TEMPLATE'])
Application Factory

Flask Blueprint
真正的好處(之一)

就是初學者
不用管這個

Flask App(s)

如剛剛的範例,是個從無到有的過程。Flask 沒有限定專案裡的檔案要如何組織。對於剛學習 Flask 的人來說,不需要先知道 Application Factories (Flask Blurprint) 的概念,就能完成一個應用。等日後到達一定的規模時,再來重構(Refactor)也不遲。

Flask App(s)

當然,對沒有經驗的初學者,可能會造成不知如何組織一個 Flask 專案的檔案架構的問題,而那依然可由文件與範例來解。

Django Settings mysite/settings.py

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

...

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'excuse'  # <- Newly added Django App
)

網址:Routing and Views

Django urls v.s. Flask app.url

Django
views & urls

mysite/urls.py
urlpatterns = patterns('',
    ...
    url(r'^$', 'excuse.views.home'),
)

Django urls

mysite/excuse/views.py
from django.http import HttpResponse

def home(request):
    excuses = [
        "It was working in my head",
        "I thought I fixed that",
        "Actually, that is a feature",
        "It works on my machine",
    ]
    return HttpResponse(excuses[0])

Django views

Django Class Base View

Django 也在 1.3 版開始支援 Class Base View

Flask
views & urls

Flask views & urls

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given (int) id
    return 'Post %d' % post_id
 

Flask View

Flask Urls

Flask Pluggable Views

> inspired by the generic views from Django :(
from flask.views import View

class ShowUsers(View):

    def dispatch_request(self):
        users = User.query.all()
        return render_template('users.html', objects=users)

app.add_url_rule('/users/',
                 view_func=ShowUsers.as_view('show_users'))
 

網頁樣版

Django template v.s. Jinja2

Django template

mysite/excuse/templates/index.html
<!DOCTYPE HTML>
<html>
<head>
    <title>Clone of Excuses For Lazy Coders</title>
</head>
<body>
    <h1> <a href="/" rel="nofollow">{{ excuse }}</a> </h1>
</body>
</html>

Flask template

myleaf/templates/index.html
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
    <h1>Hello {{ name }}!</h1>
{% else %}
    <h1>Hello World!</h1>
{% endif %}
 

乍看之下
差不多?

表單與驗證

Django Form v.s. Flask-WTF (WTForms)

Django Form

mysite/excuse/templates/index.html
from django import forms
class NameForm(forms.Form):
    your_name = forms.CharField(
        label='Your name',
        max_length=100)

Flask template

myleaf/templates/index.html
from flask_wtf import Form
from wtforms import TextField
from wtforms.validators import DataRequired

class MyForm(Form):
    name = TextField('name', validators=[DataRequired()])
 

資料庫物件

Django ORM v.s. Flask-SQLAlchemy

Django models

mysite/excuse/models.py
from django.db import models

class Excuse(models.Model):
    content = models.TextField()

    def __unicode__(self):
            return self.content
>>> from excuse.models import Excuse
>>> Excuse.objects.create(
    content="It was working in my head")

>>> Excuse.objects.all()
>>> for excuse in Excuse.objects.all():
>>>     print excuse.content
 

使用者登入

Django User v.s. Flask-Login

Django User django.contrib.auth

Flask-Login

官方文件

可以想像成把 Django auth 模組拆成 Flask auth 來用。

第三方套件與在台灣的學習資源

來 Python 社群玩

Thanks!
Questions & Answers