• 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'] }}"

  • 相关阅读:
    [原创]java WEB学习笔记97:Spring学习---Spring 中的 Bean 配置:IOC 和 DI
    [原创]java WEB学习笔记96:Spring学习---Spring简介及HelloWord
    [原创]java WEB学习笔记95:Hibernate 目录
    [原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定
    [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存
    [原创]java WEB学习笔记92:Hibernate学习之路-- -QBC 检索和本地 SQL 检索:基本的QBC 查询,带 AND 和 OR 的QBC,统计查询,排序,分页
    [原创]java WEB学习笔记91:Hibernate学习之路-- -HQL 迫切左外连接,左外连接,迫切内连接,内连接,关联级别运行时的检索策略 比较。理论,在于理解
    [原创]java WEB学习笔记90:Hibernate学习之路-- -HQL检索方式,分页查询,命名查询语句,投影查询,报表查询
    [原创]java WEB学习笔记89:Hibernate学习之路-- -Hibernate检索方式(5种),HQL介绍,实现功能,实现步骤,
    [原创]java WEB学习笔记88:Hibernate学习之路-- -Hibernate检索策略(立即检索,延迟检索,迫切左外连接检索)
  • 原文地址:https://www.cnblogs.com/jolin123/p/4510321.html
Copyright © 2020-2023  润新知