ホームページ  >  記事  >  バックエンド開発  >  PythonはDjangoフレームワークをシミュレートします

PythonはDjangoフレームワークをシミュレートします

高洛峰
高洛峰オリジナル
2017-03-02 16:27:451210ブラウズ

1. Python は Web サーバーを実装します

Web 開発には、まず Web サーバーが必要です。たとえば、Apache ですが、開発段階では、開発とデバッグの完了後にコードを安定して効率的にデプロイできる、シンプルで便利な開発サーバーを用意するのが最適です。ウェブサーバー。

# -*- coding: utf-8 -*-
from wsgiref import simple_server

# 定义一个输出 hello world 和环境变量的简单web应用程序
def hello_app(environ, start_response):
 # 输出 http 头,text/plain 表示是纯文本
 start_response('200 OK', [('Content-type','text/plain')])
 # 准备输出的内容
 content = []
 content.append('Hello world')
 for key, value in environ.items():
  content.append('%s : %s' % (key, value))
 # 输出,根据 wsgi 协议,返回的需要是一个迭代器,返回一个 list 就可以
 return ['\n'.join(content)]

# 构造开发服务器对象,设置绑定的地址和端口,并把 hello world 应用程序传给他
server = simple_server.make_server('localhost', 8080, hello_app)
# 启动开发服务器
server.serve_forever()

上記のプログラムを実行した後、ブラウザを開いて http://www.php.cn/:8080 で始まる URL にアクセスして、environ に含まれるコンテンツを確認します。


PythonはDjangoフレームワークをシミュレートします

(一部カット)


2. 基礎知識

httpプロトコルはブラウザとWebアプリケーションの間で使用され、リクエストとレスポンスの形式を指定します。


1.リクエストパッケージ(HTTPリクエスト)
リクエストには主にリクエストメソッド、リクエストURL、リクエストヘッダー、リクエストボディが含まれます。
リクエストメソッド http では GET、POST、PUT、DELETE が規定されていますが、ブラウザから開始される Web リクエストには通常、GET リクエストと POST リクエストのみが含まれます。
GET は通常、サーバーのコンテンツを取得するために使用され、POST はコンテンツの変更に似ており、PUT は追加され、DELETE は削除されます。
通常、POST リクエストは HTML フォームを送信することで開始されます。成功後にリダイレクトが必要です。
GET をプロトコルの観点から見ると、HTTP リクエストの最大の違いは、GET リクエストにはリクエスト本文がないのに対し、POST リクエストにはリクエスト本文があることです。これは、ファイルのアップロードなど、POST リクエスト
を通じて大量のデータをサーバーに送信できることを意味します。もちろん、GET リクエストは、
url などの URL 自体とそのパラメーターを通じてサーバーにパラメーターを渡すこともできます。 ?arg1=value&arg2=value
リクエストヘッダーには、リクエストされたパッケージの説明情報が含まれます。 エンコーディング、パケット長など。

2. 応答パッケージ (HTTP 応答)
http 応答パッケージの形式はより単純で、ステータス コード、応答ヘッダー、応答本文が含まれます。ステータス コードは、
200 が成功を意味するなど、リクエストの結果を示します。
404 はリソースが見つからなかったことを意味します。500 はサーバー エラーを意味します。301 はリソースのアドレスが変更されたため、クライアントがジャンプする必要があることを意味します。
応答ヘッダーはリクエスト ヘッダーと似ており、いくつかの説明情報が含まれます。応答本文は通常、出力コンテンツであり、そのほとんどはページの HTML コードです。


3. リクエストのライフサイクル
1. Web サーバーは元の http リクエストを受信した後、それをある程度パッケージ化して Web アプリケーションに配信します 2. Web アプリケーションがそれを処理した後、それを返します。特定の形式のデータを Web サーバーに送信します3. Web サーバーは、データを http 応答パケットにパッケージ化してブラウザーに返します。


4. cgi について
cgi (共通ゲートウェイインターフェース) は、Web サーバーと Web アプリケーションの間の古いプロトコルです。CGI プロトコルでは、Web サーバーが http から要求されたさまざまな情報を CGI アプリケーションの環境変数に入れます。プログラムを実行すると、CGI アプリケーションはその応答ヘッダー と対応するコンテンツを標準出力を通じて Web サーバーに出力します。
開発サーバーと上記で使用されるアプリケーションの間で使用されるプロトコルは、cgi と似ていますが、リクエストをキーと値のペアにパッケージ化します。ただし、cgi は環境変数を通じて CGI アプリケーションに渡されます。 wsgi Python の辞書オブジェクトを使用して直接渡します。
hello_app の最初のパラメーター environ は、リクエスト情報を含む辞書オブジェクトです。Web アプリケーションは、応答コンテンツ
を出力する前に、それを呼び出してステータス コードと応答ヘッダーを出力する必要があります。
Web リクエストとレスポンスの処理 ここでは、リクエストとレスポンスを処理するために webob モジュールを使用します。ここでは、最初にパッケージ管理ツールである setuptools モジュールをインストールする必要があります。このツールを使用すると、必要なソフトウェアを自動的にダウンロードできます。パッケージ。Ubuntu の app-get に似ています。アドレスは次のとおりです: http://www.php.cn/ インストールが完了したら、コマンド ラインに easy_install webob を直接入力すると、自動的にダウンロードしてインストールされます。



PythonはDjangoフレームワークをシミュレートします 使い方は簡単

>>> # webob import Request からリクエストオブジェクトをインポート>>> >>> # Request を使用して environ 辞書をラップします

>>> req = Request(environ)

Request クラスを使用して environ をラップし、そのプロパティとメソッドを通じて environ にアクセスしますリクエストオブジェクト。実際の環境辞書は Web 環境でのみ取得できるため、シェルでのテストを容易にするために、webob は単純な Web リクエストをシミュレートするメソッドを提供します。

PythonはDjangoフレームワークをシミュレートします 

也可以通过req查找其它有用的信息

PythonはDjangoフレームワークをシミュレートします  

同时也可以通过webob模块中的Response对象来包装响应信息。

PythonはDjangoフレームワークをシミュレートします

下面使用webob模块重写之前的hello_app

# -*- coding: utf-8 -*-
from wsgiref import simple_server
from webob import Request, Response


# 我们顺便增加了一个功能,就是根据用户在 URL 后面传递的参数
# 显示相应的内容
def hello_app(request):
 content = []
 # 获取 get 请求的参数
 content.append('Hello %s'%request.GET['name'])
 # 输出所有 environ 变量
 for key, value in request.environ.items():
  content.append('%s : %s' % (key, value))

 response = Response(body='\n'.join(content))
 response.headers['content-type'] = 'text/plain'
 return response

# 对请求和响应进行包装
def wsgi_wrapper(environ, start_response):
 request = Request(environ)
 response = hello_app(request)
 # response 对象本身也实现了与 wsgi 服务器之间通讯的协议,
 # 所以可以帮我们处理与web服务器之间的交互。
 # 这一句比较奇怪,对象使用括号是什么意思。。。。
 return response(environ, start_response)

server = simple_server.make_server('localhost', 8080, wsgi_wrapper)
server.serve_forever()

为了让 wsgi_wrapper 更加通用一点,可以把它设计成装饰器的形式:

# -*- coding: utf-8 -*-
from wsgiref import simple_server
from webob import Request, Response

# 写成装饰器的 wsgi_wrapper
def wsgi_wrapper(func):
 def new_func(environ, start_response):
  request = Request(environ)
  response = func(request)
  return response(environ, start_response)
 new_func.__name__ = func.__name__
 new_func.__doc__ = func.__doc__
 return new_func

# 应用程序
@wsgi_wrapper
def hello_app(request):
 content = []
 content.append('Hello %s'%request.GET['name'])
 for key, value in request.environ.items():
  content.append('%s : %s' % (key, value))

 response = Response(body='\n'.join(content))
 response.headers['content-type'] = 'text/plain'
 return response

server = simple_server.make_server('localhost', 8080, hello_app)
server.serve_forever()

三、模板
果然,还是需要用到模板,不能总是直接在Response中写上长串的html代码。
python中的模板引擎主要有mako, genshi, jinjia等。
mako 主要特点在于模板里面 可以比较方便的嵌入Python代码,而且执行效率一流;
genshi 的特点在于基于 xml, 非常简单易懂的模板语法,对于热爱xhtml的朋友来说是很好的选择,
同时也可以嵌入Python 代码,实现一些复杂的展现逻辑;
jinja genshi 一样拥有很简单的模板语法,只是不 依赖于 xml 的格式,同样很适合设计人员直接进行模板的制作,
同时也可以嵌入Python 代码实现一些复杂的展现逻辑。 

这里使用Mako,地址ttp://pypi.python.org/pypi/Mako,下载python setup.py install进行安装
简单的模块例子:

## -*- coding: utf-8 -*-
<html>
 <head>
 <title>简单mako模板</title>
 </head>
 <body>
 <h5>Hello ${name}!</h5>
 <ul>
  % for key, value in data.items():
  <li>
  ${key} - ${value}
  <li>
  % endfor
 </ul>
 </body>
</html>

保存为simple.html文件,然后需要给模板对象传递data和name两个参数,然后进行渲染,就可以输入html内容

# -*- coding: utf-8 -*-
# 导入模板对象
from mako.template import Template
# 使用模板文件名构造模板对象
tmpl = Template(filename=&#39;./simple.html&#39;, output_encoding=&#39;utf-8&#39;)
# 构造一个简单的字典填充模板,并print出来
print tmpl.render(name=&#39;python&#39;, data = {&#39;a&#39;:1, &#39;b&#39;:2})

保存为test_template.py文件,运行就可以输入内容:
$ python test_template.py

<html>
 <head>
 <title>简单mako模板</title>
 </head>
 <body>
 <h5>Hello python!</h5>
 <ul>
  <li>
  a - 1
  <li>
  <li>
  b - 2
  <li>
 </ul>
 </body>
</html>

下面对hello_app程序进行重构:
1. 把 wsgi_wrapper 单独放到通用模块 utils.py:

# -*- coding: utf-8 -*-
from webob import Request

def wsgi_wrapper(func):
 def new_func(environ, start_response):
  request = Request(environ)
  response = func(request)
  return response(environ, start_response)
 new_func.__name__ = func.__name__
 new_func.__doc__ = func.__doc__
 return new_func

2. 把 hello_app 给彻底独立出来,形成单独的模块 controller.py :

# -*- coding: utf-8 -*-
from utils import wsgi_wrapper
from webob import Response
from mako import Template

# 整合了模板功能的 hello_app
@wsgi_wrapper
def hello_app(request):
 tmpl = Template(filename=&#39;./simple.html&#39;, output_encoding=&#39;utf-8&#39;)
 content = tmpl.render(name=request.GET[&#39;name&#39;], data=request.environ)
 return Response(body=content)

3. 这样 main.py 就变成这样了:

# -*- coding: utf-8 -*-
from wsgiref import simple_server
from controller import hello_app

server = simple_server.make_server(&#39;localhost&#39;, 8080, hello_app)
server.serve_forever()

四、ORM(Object Relation Mapping, 对象关系映射)
终于也要这一步了,作为web应用,还是需要与数据库进行合作。
这里使用sqlalchemy,是一个 ORM (对象-关系映射)库,提供Python对象与关系数据库之间的映射。和Django的models
用法很像,也是可以通过python代码来创建数据库表,并进行操作。
sqlalchemy 还可以自动映射 Python 对象的继承,可以实现eager loading、lazy loading, 可以直接将 Model 映射到自定
义的 SQL 语句,支持n多的数据库等等等等。 可以说 sqlalchemy 既有不输于 Hibernate 的强大功能,同时不失 Python
的简洁优雅。
使用方法:

# -*- coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base

# 创建数据库引擎,这里我们直接使用 Python2.5 自带的数据库引擎:sqlite,
# 直接在当前目录下建立名为 data.db 的数据库
engine = create_engine(&#39;sqlite:///data.db&#39;)
# sqlalchemy 中所有数据库操作都要由某个session来进行管理
# 关于 session 的详细信息请参考:http://www.sqlalchemy.org/docs/05/session.html
Session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()

class Dictionary(Base):
 # Python 对象对应关系数据库的表名
 __tablename__ = &#39;t_dictionary&#39;
 # 定义自动,参数含义分别为:数据库字段名,字段类型,其他选项
 key = Column(&#39;key&#39;, String(255), primary_key=True)
 value = Column(&#39;value&#39;, String(255))

# 创建数据库
Base.metadata.create_all(engine)

session = Session()
for item in [&#39;python&#39;,&#39;ruby&#39;,&#39;java&#39;]:
 # 构造一个对象
 dictionary = Dictionary(key=item, value=item.upper())
 # 告诉 sqlalchemy ,将该对象加到数据库
 session.add(dictionary)

# 提交session,在这里才真正执行数据库的操作,添加三条记录到数据库
session.commit()

# 查询数据库中Dictionary对象对应的数据
for dictionary in session.query(Dictionary):
 print dictionary.key, dictionary.value

上面的代码你执行两遍就会报错,为什么。。。因为插入数据库的主键重复了。。。。
 这样就可以整合到之前的controller.py文件中

# -*- coding: utf-8 -*-
from utils import wsgi_wrapper
from webob import Response
from mako.template import Template
# 导入公用的 model 模块
from model import Session, Dictionary

@wsgi_wrapper
def hello_app(request):
 session = Session()
 # 查询到所有 Dictionary 对象
 dictionaries = session.query(Dictionary)
 # 然后根据 Dictionary 对象的 key、value 属性把列表转换成一个字典
 data = dict([(dictionary.key, dictionary.value) for dictionary in dictionaries])

 tmpl = Template(filename=&#39;./simple.html&#39;, output_encoding=&#39;utf-8&#39;)
 content = tmpl.render(name=request.GET[&#39;name&#39;], data=data)
 return Response(body=content)

五、URL分发控制
给不同的资源设计不同的 URL, 客户端请求这个 URL,web应用程序再根据用户请求的 URL 定位到具体功能并执行之。
提供一个干净的 URL 有很多好处:
1. 可读性,通过 URL 就可以大概了解其提供什么功能
2. 用户容易记住也方便直接输入
3.设计良好的 URL 一般都更短小精悍,对搜索引擎也 更友好
使用selector模块来处理url映射
下载地址http://pypi.python.org/pypi/selector, 下载那个source文件进行python setup.py install
 首先把urls的配置单独放到urls.py中

# -*- coding: utf-8 -*-
from controller import hello_app
mappings = [(&#39;/hello/{name}&#39;, {&#39;GET&#39;:hello_app})]

修改main.py

# -*- coding: utf-8 -*-
from wsgiref import simple_server
from urls import mappings
from selector import Selector

# 构建 url 分发器
app = Selector(mappings)
server = simple_server.make_server(&#39;localhost&#39;, 8080, app)
server.serve_forever()

然后,在 hello_app 中就可以通过 environ['wsgiorg.routing_args'] 获取到 name 参数了,
不过在 wsgi_wrapper 其实还可以进一步简化 hello_app 的工作: 直接把解析得到的参数
当作函数参数传过去!修改 utils.py:

from webob import Request

def wsgi_wrapper(func):
 def new_func(environ, start_response):
  request = Request(environ)
  position_args, keyword_args = environ.get(&#39;wsgiorg.routing_args&#39;, ((), {}))
  response = func(request, *position_args, **keyword_args)
  return response(environ, start_response)
 new_func.__name__ = func.__name__
 new_func.__doc__ = func.__doc__
 return new_func

那 hello_app 就可以改成这样了:

...
@wsgi_wrapper
def hello_app(request, name=&#39;&#39;):
 ...
 content = tmpl.render(name=name, data=data)
 return Response(body=content)
执行main.py,访问http://localhost:8080/hello/Python

总结
以上部分的实现,就是类似Django框架中的几个主要的功能模块,希望对大家的学习有所帮助。

更多PythonはDjangoフレームワークをシミュレートします相关文章请关注PHP中文网!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。