• tornado学习笔记(四)


    4 Databases

    1 pymongo

    pymongo是python用来连接MongoDB数据库的一个库,可以pip安装:pip install pymongo

    命令行mongod运行mongodb服务器后,可以使用pymongo来进行连接

    >>> import pymongo
    >>> client = pymongo.MongoClient('localhost', 27017)
    >>> db = client.emample
    # db = client['example']
    

    这样就有了可以使用数据库db

    collection:一个数据库可以有任意多个collections(集合). 一个collection是放一些相关文档(documents)的地方,我们使用的大多数mongodb操作都是在collections上进行

    查看数据库中的集合列表:

    >>> db.collection_names()
    []
    

    创建一个集合并插入一个键值对:

    >>> widgets = db.widgets # widgets = db['widgets']
    >>> widgets
    Collection(Database(MongoClient('localhost', 27017), u'example'), u'widgets')
    >>> widgets.insert({"foo": "bar"})
    ObjectId('...')
    >>> db.colection_names()
    [u'system.indexes', u'widgets']
    

    可以发现访问一个集合有两种方法,一种是作为数据库对象的一个属性,一种是以字典的形式通过集合名字作为关键字

    mongodb的集合以document文档的形式来存储数据,如每次在集合中insert的一个字典就是一个文档,返回的ObjectId就是这个文档对象的id.

    find_one函数可以在集合中查找一个文档对象,参数是这个字典中的一个键值对,返回整个文档,也就是一个字典的形式,支持字典的操作,eg,

    >>> widgets.insert({"name": "flibnip",
                        "description": "grade-A industrial flibnip",
                        "quantity": 3})
    ObjectId(...)
    
    >>> widgets.find_one({"name": "flibnip"})
    {u'description':u'grade-A',
     u'_id': ObjectId(...),
     u'name':...,
     u'quantity':...}
    
    >>> doc = widgets.find_one({"name": "flibnip"})
    >>> type(doc)
    <type  'dict'>
    >>> print doc['name']
    flibnip
    

    直接在返回的字典上对数据进行修改,不会影响到数据库中的值,只有通过save函数才能将修改写到数据库

    >>> doc['quantity'] = 4
    >>> db.widgets.save(doc)
    >>> print widgets.find_one({"name": "flibnip"})['quantity']
    4
    

    在增加一些文档

    >>> widgets.insert({"name": "smorkeg", 
                        "description": "for external use only", 
                        "quantity": 4})
    ObjectId('4eadaa5c136fc4aa41000002')
    >>> widgets.insert({"name": "clobbasker", 
                        "description":  "properties available on request",
                         "quantity": 2})
    ObjectId('4eadad79136fc4aa41000003')
    

    find函数可以查找拥有某些键值对的一组文档,不带参数则返回集合中的所有文档

    >>> for doc in widgets.find():
    >>>     print doc
    {u'_id': ObjectId('4eada0b5136fc4aa41000000'), u'foo': u'bar'}
    {u'description': u'grade-A',
    u'_id': ObjectId('4eada3a4136fc4aa41000001'),
    u'name': u'flibnip', u'quantity': 4}
    {u'description': u'for external use only',
    u'_id': ObjectId('4eadaa5c136fc4aa41000002'),
    u'name': u'smorkeg', u'quantity': 4}
    {u'description': u'properties available on request',
    u'_id': ObjectId('4eadad79136fc4aa41000003'),
    u'name': u'clobbasker',
    u'quantity': 2}
    
    
    >>> for doc in widgets.find({"quantity":4})
    ...     print doc
    {u'description': u'grade-A',
    u'_id': ObjectId('4eada3a4136fc4aa41000001'),
    u'name': u'flibnip', u'quantity': 4}
    {u'description': u'for external use only',
    u'_id': ObjectId('4eadaa5c136fc4aa41000002'),
    u'name': u'smorkeg',
    u'quantity': 4}
    

    remove函数从一个集合中删除满足条件的所有文档,用法与find_one,find类似

    2 simple word dictionary

    创建一个web的简单字典,用mongodb作为数据库,可以通过url来进行查询,eg

    $ curl http://localhost:8000/oarlock
    {definition: "A device attached to a rowboat to hold the oars in place",
    "word": "oarlock"}
    

    使用post可以创建一个单词,如果该单词已经存在则修改它的定义

    $ curl -d definition=a+leg+shirt http://localhost:8000/pants
    {"definition": "a leg shirt", "word": "pants"}
    

    definitions_readwrite.py

    import tornado.httpserver
    import tornado.ioloop
    import tornado.options
    import tornado.web
    
    import pymongo
    
    from tornado.options import define, options
    define("port", default=8000, help="run on the given port", type=int)
    
    class Application(tornado.web.Application):
        def __init__(self):
            handlers = [(r"/(w+)", WordHandler)]
            conn = pymongo.MongoClient("localhost", 27017)
            self.db = conn.example
            tornado.web.Application.__init__(self, handlers, debug=True)
    
    class WordHandler(tornado.web.RequestHandler):
        def get(self, word):
            coll = self.application.db.words
            word_doc = coll.find_one({"word": word})
            if word_doc:
                del word_doc["_id"]
                self.write(word_doc)
            else:
                self.set_status(404)
                self.write({"error": "word no found"})
        def post(self, word):
            definition = self.get_argument("definition")
            coll = self.application.db.words
            word_doc = coll.find_one({"word": word})
            if word_doc:
                word_doc["definition"] = definition
                coll.save(word_doc)
            else:
                word_doc = {"word":word, "definition": definition}
                coll.insert(word_doc)
            del word_doc["_id"]
            self.write(word_doc)
    
    if __name__ == "__main__":
        tornado.options.parse_command_line()
        http_server = tornado.httpserver.HTTPServer(Application())
        http_server.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()
    

    先看服务器是怎样链接数据库的,在Application类的初始化中,定义了一个db属性,这就是我们使用的数据库

    conn = pymongo.Connection("localhost", 27017)
    self.db = conn.example
    

    有了这个db属性后,我们就可以通过RequestHandler类的self.application.db来进行访问

    在WordHandler中,定义了get和post两种方式,get是简单的查询某个单词,在write(word_doc)之前要去掉字典中的'_id',因为write会自动把字典转化为JSON. post模式先通过self.get_argument("definition")获取单词定义,然后查询该单词是否存在,已经存在就用save函数保存新的修改,没有存在就用insert函数插入新单词

    3 Burts books

    read from database

    前面的Burt's的例子,现在增加mongodb数据库的操作

    mport os.path
    import tornado.auth
    import tornado.escape
    import tornado.httpserver
    import tornado.ioloop
    import tornado.options
    import tornado.web
    from tornado.options import define, options
    import pymongo
    
    define("port", default=8000, help="run on the given port", type=int)
    
    class Application(tornado.web.Application):
        def __init__(self):
            handlers = [
                (r"/", MainHandler),
                (r"/recommended/", RecommendedHandler),
            ]
            settings = dict(
                template_path=os.path.join(os.path.dirname(__file__), "templates"),
                static_path=os.path.join(os.path.dirname(__file__), "static"),
                ui_modules={"Book": BookModule},
                debug=True,
            )
            conn = pymongo.MongoClient("localhost", 27017)
            self.db = conn["bookstore"]
            tornado.web.Application.__init__(self, handlers, **settings)
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.render(
                "index.html",
                page_title="Burt's Books | Home",
                header_text="Welcome to Burt's Books!",
            )
    
    class RecommendedHandler(tornado.web.RequestHandler):
        def get(self):
            coll = self.application.db.books
            books = coll.find()
            self.render(
                "recommended.html",
                page_title="Burt's Books | Recommended Reading",
                header_text="Recommended Reading",
                books=books
            )
    
    class BookModule(tornado.web.UIModule):
        def render(self, book):
            return self.render_string(
                "modules/book.html",
                book=book,
            )
        def css_files(self):
            return "css/recommended.css"
        def javascript_files(self):
            return "js/recommended.js"
    
    def main():
        tornado.options.parse_command_line()
        http_server = tornado.httpserver.HTTPServer(Application())
        http_server.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()
    
    if __name__ == "__main__":
        main()
    

    主要就是在Application类里面增加数据库self.db = conn.bookstore,在RecommendedHandler中,通过books = coll.find()的到所有书目的字典,然后进行展示即可,其中每一个书目都用模块BookModule来处理。现在的功能只是可以显示数据库中已有的书目

    editing and adding books

    增加一个表格形式给用户增加书目,表格提交后需要一个handler来处理,将数据写进数据库中

    实现类BookEditHandler,有get和post两种模式,关联的url如下:

    handlers = [
        ...
        (r"/edit/(0-9Xx-]+)", BookEditHandler),
        (r"/add", BookEditHandler),
    ]
    

    用户要增加新书目时可以访问localhost:8000/add,会返回填写表单的网页,然后点击提交后会以post的方式再次访问这个url,这时BookEditHandler的post类就会处理,将数据写进数据库。或者用户要修改某书目的数据,以get的访问如/localhost:8000/edit/0-123-456,edit后面为书目的isbn,就可以返回该书目的表单修改界面,里面保留原本的书目数据,修改后点击提交也会重新以post的形式访问这个url来更新数据

    下面是BookEditHandler类的实现:

    class BookEditHandler(tornado.web.RequestHandler):
        def get(self, isbn=None):
            book = dict()
            if isbn:
                coll = self.application.db.books
                book = coll.find_one({"isbn": isbn})
            self.render("book_edit.html",
                        page_title="Burt's Books",
                        header_text="Edit book",
                        book=book)
    
        def post(self, isbn=None):
            import time
    
            book_fields = ['isbn', 'title', 'subtitle', 'image', 'author',
                           'date_released', 'description']
            coll = self.application.db.books
            book = dict()
            if isbn:
                book = coll.find_one({"isbn": isbn})
            for key in book_fields:
                book[key] = self.get_argument(key, None)
    
            if isbn:
                coll.save(book)
            else:
                book['date_added'] = int(time.time())
                coll.insert(book)
            self.redirect("/recommended/")
    

    get函数中,首先判断isbn,如果存在说明是要修改书目内容,没有则是增加新书目。在数据库中find_one根据isbn查找数据然后返回book_edit.html的表单填写页面

    post函数中,也是通过isbn判断是否是新书目,最后分别用save或者insert来写进数据库,然后将用户重定向到/recommended/的页面来查看修改结果

    book_edit.html

    {% extends "main.html" %}
    {% autoescape None %}
    
    {% block body %}
    <form method="POST">
        ISBN <input type="text" name="isbn"
            value="{{ book.get('isbn', '') }}"><br>
        Title <input type="text" name="title"
            value="{{ book.get('title', '') }}"><br>
        Subtitle <input type="text" name="subtitle"
            value="{{ book.get('subtitle', '') }}"><br>
        Image <input type="text" name="image"
            value="{{ book.get('image', '') }}"><br>
        Author <input type="text" name="author"
            value="{{ book.get('author', '') }}"><br>
        Date released <input type="text" name="date_released"
            value="{{ book.get('date_released', '') }}"><br>
        Description<br>
        <textarea name="description" rows="5"
            cols="40">{% raw book.get('description', '')%}</textarea><br>
        <input type="submit" value="Save">
    </form>
    {% end %}
    

    这里书目的每项属性都用get函数来获取,如果字典中没有这个感觉在则设置为'',表单每项的name都是和数据库中的属性名相同,方便提交之后写进数据库

    最后在recommended的页面中,给显示的每个数目增加一个edit链接,点击可以直接进入修改页面

    <div class="book" style="overflow: auto">
      <h3 class="book_title">{{ book["title"] }}</h3>
      {% if book["subtitle"] != "" %}
            <h4 class="book_subtitle">{{ book["subtitle"] }}</h4>
        {% end %}
      <img src="{{ book["image"] }}" class="book_image"/>
        <div class="book_details">
          <div class="book_date_released">Released: {{ book["date_released"]}}</div>
          <div class="book_date_added">Added: {{ locale.format_date(book["date_added"], relative=False) }}</div>
          <h5>Description:</h5>
            <div class="book_body">{% raw book["description"] %}</div>
            <p><a href="/edit/{{ book['isbn'] }}">Edit</a></p>
        </div>
    </div>
    

    链接是href="/edit/{{ book['isbn'] }}"

  • 相关阅读:
    如何:为 Silverlight 客户端生成双工服务
    Microsoft Sync Framework 2.1 软件开发包 (SDK)
    Windows 下的安装phpMoAdmin
    asp.net安全检测工具 Padding Oracle 检测
    HTTP Basic Authentication for RESTFul Service
    Windows系统性能分析
    Windows Server AppFabric Management Pack for Operations Manager 2007
    Mongo Database 性能优化
    服务器未能识别 HTTP 标头 SOAPAction 的值
    TCP WAIT状态及其对繁忙的服务器的影响
  • 原文地址:https://www.cnblogs.com/jolin123/p/4510321.html
Copyright © 2020-2023  润新知