• MongoEngine中文参考


     

    在MongoDB里面,一条文档大致相当于关系型数据库里面的一行。在关系型数据库里面,行是被存储在表里面,并且有一个严格的结构。MongoDB里面把文档存储在集合里面而不是存在表里面,最根本上的不同就是在数据库层面上没有强制的结构限制。

    定义一个文档纲要

    MongoEngine允许你为文档定义一个纲要这可以帮你减少编码错误,让你利用现有的字段来定义各种功能的函数。

    定义一个文档的纲要,首先需要创建一个继承 Document 的类。文档的字段都被作为这个继承类的属性。

    from mongoengine import *  

    import datetime

    class Page(Document):  

        title = StringField(max_length=200, required=True)  

        date_modified = DateTimeField(default=datetime.datetime.now)

    动态文档纲要 MongoDB的一个好处就是为集合定义动态的纲要,这在有动态文档的场景下能让数据有组织,有计划的存储。

    动态文档与一般文档的工作方式一样,但是任何为它们设置的数据或属性也会被存储

    from mongoengine import *

    class Page(DynamicDocument):  

        title = StringField(max_length=200, required=True)

    # Create a new page and add tags  >>> page = Page(title='Using MongoEngine')  

    >>> page.tags = ['mongodb', 'mongoengine']a>>> page.save()

    >>> Page.objects(tags='mongoengine').count()  

    >>> 1

    字段

    在默认情况下,字段可以不需要。让一个字段强制存在,可以将这个字段的 require 关键字设置为 true 。字段也可以有验证限制。字段也可以设置默认值,在字段没有被提供值的时候会用到。可以使用的字段类型如下:

    BinaryField

    BooleanField

    ComplexDateTimeField

    DateTimeField

    DecimalField

    DictField

    DynamicField

    EmailField

    EmbeddedDocumentField

    FileField

    FloatField

    GenericEmbeddedDocumentField

    GenericReferenceField

    GeoPointField

    ImageField

    IntField

    ListField

    MapField

    ObjectIdField

    ReferenceField

    SequenceField

    SortedListField

    StringField

    URLField

    UUIDField

    字段参数

    db_field(default: None)

    mongodb字段名

    name(default: None)

    mongoengine字段名

    required(default: False)

    如果设置为True,那么在存储数据的时候,如果这个字段为空,在验证的时候会产生ValidateError。

    default(default: None)

    为字段设置默认值。

    default这个参量的定义是遵循 the general rules on Python,实例如下:

    class ExampleFirst(Document):  

        # Default an empty list      values = ListField(IntField(), default=list)

    class ExampleSecond(Document):  

        # Default a set of values      values = ListField(IntField(), default=lambda: [1,2,3])

    class ExampleDangerous(Document):  

        # This can make an .append call to  add values to the default (and all the following objects),      # instead to just an object      values = ListField(IntField(), default=[1,2,3])  

        unique(default: False)

    如果设置为True,那么同一个collection里面不能有一个document与它的值相同。

    unique_with(default: None)

    让一个字段与该字段一同设置为unique

    primary_key(default: False)

    如果设置为True,那么这个字段被设置为主键。

    choices(default: None)

    当字段的值需要限制的时候设置一个可迭代的list或者tuple,也可以是一个嵌套的tuple。

    SIZE = (('S', 'Small'),  

            ('M', 'Medium'),  

            ('L', 'Large'),  

            ('XL', 'Extra Large'),  

            ('XXL', 'Extra Extra Large'))

    class Shirt(Document):  

        size = StringField(max_length=3, choices=SIZE)

    或者只包含值的也可以

    SIZE = ('S', 'M', 'L', 'XL', 'XXL')

    class Shirt(Document):  

        size = StringField(max_length=3, choices=SIZE)

    help_text(default: None) 在使用这个字段的时候输出帮助---在使用表单的时候用到。

    verbose_name(default: None) 为这个字段起更能让人接受的名字---在使用表单的时候用到。

    列表字段

    mongodb里面允许你存储list。给document添加一个list字段,使用ListField类型,ListField把另一个类型的对象作为它的第一个参数,用来指定在list里面存储的数据类型。

    class Page(Document):  

        tags = ListField(StringField(max_length=50))

    嵌入的document mongodb能够存储嵌入的document。需要为这些document定义Schemata,它们也是规范的document。 定义嵌入的document的时候,像往常一样定义一个document,但是要继承EmbeddedDocument而不是Document:

    class Comment(EmbeddedDocument):  

        content = StringField()

    在document中嵌入另一个document,使用 EmbeddedDocumentField 类型。第一个参数是嵌入document的类:

    class Page(Document):  

        comments = ListField(EmbeddedDocumentField(Comment))

     comment1 = Comment(content='Good work!')  

     comment2 = Comment(content='Nice article!')  

     page = Page(comments=[comment1, comment2])

    字典字段 通常,会使用嵌入document来代替字典----总的来说字典不支持任何类型检查与约束。可是,有时候你不知道你想存储的数据是什么类型,这时候使用 DictField会比较合适:

    class SurveyResponse(Document):  

        date = DateTimeField()  

        user = ReferenceField(User)  

        answers = DictField()

    survey_response = SurveyResponse(date=datetime.now(), user=request.user)  

    response_form = ResponseForm(request.POST)  

    survey_response.answers = response_form.cleaned_data()  

    survey_response.save()

    引用字段 引用字段用来引用在数据库里面存储的其他document,使用 ReferenceField ,在构造器中把另一个document的类作为第一个参数,然后就可以简单地指定document到这个字段。

    class User(Document):  

        name = StringField()

    class Page(Document):  

        content = StringField()  

        author = ReferenceField(User)

    john = User(name="John Smith")  

    john.save()

    post = Page(content="Test Page")  

    post.author = john 

    post.save()

    User对象自动成为了引用类,在检索Page的时候会间接引用User。 当引用字段引用的是自身的时候,在ReferenceField 的构造器中添加 'self' 作为它的参数,如果引用还未定义的document,则使用应用类的类名作为构造器参数:

    class Employee(Document):  

        name = StringField()  

        boss = ReferenceField('self')  

        profile_page = ReferenceField('ProfilePage')

    class ProfilePage(Document):  

        content = StringField()

    使用ListField的一对多
    如果你想利用一个引用的list来实现一对多,那么引用会被存储成 DBRefs ,那么需要查询的时候,你也需要通过这个对象来进行查询。

    class User(Document):  

        name = StringField()

    class Page(Document):  

        content = StringField()  

        authors = ListField(ReferenceField(User))

    bob = User(name="Bob Jones").save()  

    john = User(name="John Smith").save()

    Page(content="Test Page", authors=[bob, john]).save()  

    Page(content="Another Page", authors=[john]).save()

    # Find all pages Bob authored  Page.objects(authors__in=[bob])

    # Find all pages that both Bob and John have authored  Page.objects(authors__all=[bob, john])

    处理删除引用的document 默认情况下,mongodb不会检查数据的完整性,如果删除了其他document正在引用的document会引发一致性的问题。mongoengine的ReferenceField 添加了一些功能来维持数据一致性,为没一个引用提供了删除规则。删除规则通过声明ReferenceField 的reverse_delete_rule 属性来指定,就像这样:

    class Employee(Document):  

        ...  

        profile_page = ReferenceField('ProfilePage', reverse_delete_rule=mongoengine.NULLIFY)

    这个例子中的声明定义了如果一个Employee对象删除,与它关联的ProfilePage也会删除。如果一批Employee对象被删除,那么与它关联的ProfilePage也会被删除。 它的值也可以被设置成如下的常量:

    mongoengine.DO_NOTHING

    这是默认值不做任何事。在删除的时候速度比较快,但是会带来数据不一致和空引用的问题。

    mongoengine.DENY

    如果仍有document引用到这个对象,那么会阻止删除

    mongoengine.NULLIFY

        任何对象的字段关联到这个对象的如果被删除,那么这个document也会被删除,关联关系作废。

    mongoengine.CASCADE

        任何对象的字段引用到这个对象的会被先删除

    mongoengine.PULL

       移除对于对象的引用关系

    通用引用字段

    一种次选的引用字段也是存在的, GenericReferenceField 。它可以让你引用任何类型的document,因此它不用其他document的类来作为它的参数:

    class Link(Document):  

        url = StringField()

    class Post(Document):  

        title = StringField()

    class Bookmark(Document):  

        bookmark_object = GenericReferenceField()

    link = Link(url='http://hmarr.com/mongoengine/')  

    link.save()

    post = Post(title='Using MongoEngine')  

    post.save()

    Bookmark(bookmark_object=link).save()  

    Bookmark(bookmark_object=post).save()

    唯一性约束 mongoengine里面允许你制定字段在collection里面的值是唯一的,通过在构造器里面指定 unique=True 如果你想在数据库里存储已存在的value的document,会引发OperationError。你也可以通过使用unique_with来设置多字段的唯一性约束,它的值可以是一个字段名,或者是存储了字段名的list或tuple。

    class User(Document):  

        username = StringField(unique=True)  

        first_name = StringField()  

        last_name = StringField(unique_with='first_name')

    在保存时跳过document验证 你可以在使用save()的时候通过设置validate=False 来在保存的时候跳过验证

    class Recipient(Document):  

        name = StringField()  

        email = EmailField()

    recipient = Recipient(name='admin', email='root@localhost')  

    recipient.save()               # will raise a ValidationError while  recipient.save(validate=False) # won't  Document Collection

    document对象是直接继承于Document ,会在数据库里面拥有它们自己的collection。这个collection的名字默认就是类的名字,被转化成了小写。如果你想改变这个collection的名字,可以在类里面创建一个字典属性叫meta,然后可以随意设置这个collection的名字了。

    class Page(Document):  

        title = StringField(max_length=200, required=True)  

        meta = {'collection': 'cmsPage'}

    索引 你可以在document里面指定索引来使查询的时候速度更快。这个可以通过在meta字典里声明一个叫键为 'indexes', 值为存放索引规则的list的键值对来实现,一个索引规则可以是一个字段名,或者是由几个字段名组成的tuple,也可以是一个包含完整索引声明的字典。可以在字段名前面加上+ 或者-来指定索引的顺序。这只会在联合索引中有效果。

    class Page(Document):  

        title = StringField()  

        rating = StringField()  

        meta = {  

            'indexes': ['title', ('title', '-rating')]  

        }

    meta字典中还有一下的选项可选: fields (Default: None) 产生索引的字段,声名的方法与以上一样。

    types (Default: True)

       索引是否应该添加 _type字段

    sparse (Default: False)

       索引是否需要备份

    unique (Default: False)

       索引是否需要备份

    地理空间索引

    地理空间索引会自动为所有的 GeoPointField 创建。

    也可以来明确地指定地理空间索引。这在你需要定义一个DictField 的子域或者自己定制的包含一个点的字段的索引的时候很有用。创建地理空间索引的时候需要在字段名前面加 *:

    class Place(Document):  

        location = DictField()  

        meta = {  

            'indexes': [  

                '*location.point',  

            ],  

        }

    顺序 在meta里面设置ordering的值可以指定你的QuerySet 的默认顺序。在 QuerySet被创建的时候顺序规则会被应用 ,它也可以通过使用 order_by() 来复写。

    from datetime import datetime

    class BlogPost(Document):  

        title = StringField()  

        published_date = DateTimeField()

        meta = {  

            'ordering': ['-published_date']  

        }

    blog_post_1 = BlogPost(title="Blog Post #1")  

    blog_post_1.published_date = datetime(2010, 1, 5, 0, 0 ,0)

    blog_post_2 = BlogPost(title="Blog Post #2")  

    blog_post_2.published_date = datetime(2010, 1, 6, 0, 0 ,0)

    blog_post_3 = BlogPost(title="Blog Post #3")  

    blog_post_3.published_date = datetime(2010, 1, 7, 0, 0 ,0)

    blog_post_1.save()  

    blog_post_2.save()  

    blog_post_3.save()

    # get the "first" BlogPost using default ordering  # from BlogPost.meta.ordering  latest_post = BlogPost.objects.first()  

    assert latest_post.title == "Blog Post #3"

    # override default ordering, order BlogPosts by "published_date"  first_post = BlogPost.objects.order_by("+published_date").first()  

    assert first_post.title == "Blog Post #1"

    共享键 如果你的collection是共享的,那么你需要指定一个存储共享键的tuple, 使用mongoengine.Document.meta里面的shard_key属性,

    class LogEntry(Document):  

        machine = StringField()  

        app = StringField()  

        timestamp = DateTimeField()  

        data = StringField()

        meta = {  

            'shard_key': ('machine', 'timestamp',)  

        }

    Document继承 为了创建一个你定义的类型的document,你必须继承document并且加上一些你需要的字段和方法。如果这不是一个直接继承document的子类,那么这个类的数据不会存放在自己的collection中,而会存放在它的父类的collection里面。这能在检索关联的document的时候提供更多的方便。

    # Stored in a collection named 'page'  class Page(Document):  

        title = StringField(max_length=200, required=True)

        meta = {'allow_inheritance': True}

    # Also stored in the collection named 'page'  class DatedPage(Page):  

        date = DateTimeField()

    处理现有的数据 为了改正这种层次的document涉及的检索,在数据库里面的document会存储另两个属性:_cls 和 _types。这些在mongoengine的接口中对用户是隐藏的,可能在使用mongoengine处理一个已经存在的数据库的时候不会呈现出来。你可能会需要禁止这个类的继承,方法如下:

    # Will work with data in an existing collection named 'cmsPage'  class Page(Document):  

        title = StringField(max_length=200, required=True)  

        meta = {  

            'collection': 'cmsPage',  

            'allow_inheritance': False,  

         }

    mongoengine使用笔记

    Sat 23 June 2012

    最近重新拾起Django,但是Django并不支持mongodb,但是有一个模块mongoengine可以实现Django Model类似的封装.但是mongoengine的中文文档几乎没有,有的也是简短的几句介绍和使用.下面我就分享一下我在使用过程中所记录下的一些笔记,可能有点乱.大家可以参考一下.

    安装mongoengine

    easy_install pymongo # 依赖库

    easy_install mongoengine

    基本使用

    from mongoengine import *

    from datetime import datetime

    # 连接数据库

    connect('blog')   # 连接本地blog数据库

    # 如需验证和指定主机名

    # connect('blog', host='192.168.3.1', username='root', password='1234')

    # 定义分类文档

    class Categories(Document):

        ' 继承Document类,为普通文档 '

        name = StringField(max_length=30, required=True)

        artnum = IntField(default=0, required=True)

        date = DateTimeField(default=datetime.now(), required=True)

    和Django的model使用很类似,所以也不解释什么.

    插入

    cate = Categories(name="Linux")   # 如果requiredTrue则必须赋予初始值,如果有default,赋予初始值则使用默认值

    cate.save() # 保存到数据库

    查询和更新

    文档类有一个 objects 属性.我们使用它来查询数据库.

    # 返回集合里的所有文档对象的列表

    cate = Categories.objects.all()

    # 返回所有符合查询条件的结果的文档对象列表

    cate = Categories.objects(name="Python")

    # 更新查询到的文档:

    cate.name = "LinuxZen"

    cate.update()

    查询数组 默认查询数组"="代表的意思是in:

    class Posts(Document):

        artid = IntField(required=True)

        title = StringField(max_length=100, required=True)

        content = StringField(required=True)

        author = ReferenceField(User)

        tags = ListField(StringField(max_length=20, required=True), required=True)

        categories = ReferenceField(Categories), required=True)

        comments = IntField(default=0, required=True)

    # 将会返回所有tags包含coding的文档

    Posts.objects(tags='coding')

    ReferenceField 引用字段:

    通过引用字段可以通过文档直接获取引用字段引用的那个文档:

    class Categories(Document):

        name = StringField(max_length=30, required=True)

        artnum = IntField(default=0, required=True)

        date = DateTimeField(default=datetime.now(), required=True)

    class Posts(Document):

        title = StringField(max_length=100, required=True)

        content = StringField(required=True)

        tags = ListField(StringField(max_length=20, required=True), required=True)

        categories = ReferenceField(Categories)

    插入引用字段

    cate =Categories(name="Linux")

    cate.save()

    post = Posts(title="Linuxzen.com", content="Linuxzen.com",tags=["Linux","web"], categories=cate)

    post.save()

    通过引用字段直接获取引用文档对象

    一般文档查询会返回一个列表(尽管只有一个结果),我们想要获得一个文档对象可以使用索引获取第一个文档对象,但是mongoengine建议使用first()来获取第一个:

    >>> cate = Posts.objects.all().first().categories

    >>> cate

    >>> cate.name

    u'Linux'

    查询包含Linux分类的文章

    >>> cate = Categories.objects(name="Linux").first()

    >>> Posts.objects(categories=cate)

    EmbeddedDocument 嵌入文档

    继承EmbeddedDocument的文档类就是嵌入文档,嵌入文档用于嵌入其他文档的EmbeddedDocumentField 字段,比如上面例子的tags字段如果改成嵌入文档的话可以将Posts文档类改成如下方式:

    class Posts(Document):

        title = StringField(max_length=100, required=True)

        content = StringField(required=True)

        tags = ListField(EmbeddedDocumentField('Tags')required=True)

        categories = ReferenceField(Categories)

    还需要添加一个Tags嵌入文档类:

    class Tags(EmbeddedDocument):

    name = StringField()

    date = DateTimeField(default=datetime.now())

    我们像如下方式插入Posts文档中的Tags

    >>> tag = Tags(name="Linuxzen")

    >>> post = Posts(title="Linuxzen.com", content="Linuxzen.com", tags=[tag], categories=cate)

    >>> tag = Tags(name="mysite")

    >>> post.tags.append(tag)

    >>> post.save()

    >>> tags = post.tags

    >>> for tag in tags:

    print tag.name

    Linuxzen

    mysite

    时间段查询

        start = datetime(int(year), int(month), 1)

        if int(month) + 1 > 12:

            emonth = 1

            eyear = int(year) + 1

        else:

            emonth = int(month) + 1

            eyear = int(year)

        end = datetime(eyear, emonth, 1)

        articles = Posts.objects(date__gte=start, date__lt=end).order_by('-date')

    分片

    slice用于分片

    # comments - skip 5, limit 10

    Page.objects.fields(slice__comments=[5, 10])

    # 也可以使用索引值分片

    # limit 5

    users = User.objects[:5]

    # skip 5

    users = User.objects[5:]

    # skip 10, limit 15

    users = User.objects[10:15]

    使用原始语句查询

    如果想使用原始的pymongo查询方式可以使用__raw__操作符 Page.objects(raw={'tags':'coding'}) 使用$inc和$set操作符

    # 更新嵌入文档comments字段by的值为joe的文档字段votes增加1

    Page.objects(comments_by="joe").update(inc__votes=1)

    # 更新嵌入文档comments字段by的值为joe的文档字段votes设置为1

    Page.objects(comments_by="joe").update(set__votes=1)

    其他技巧

    #查询结果转换成字典

    users_dict = User.objects().to_mongo()

    # 排序,按日期排列

    user = User.objects.order_by("date")

    # 按日期倒序

    user = User.objects.order_by("-date")

  • 相关阅读:
    json返回数据拼接HTML
    jquery文本框验证字符长度和只能输入数字
    DataTable转换为Json格式
    将集合类转换成DataTable
    class创建单击事件
    ajax局部刷新分页
    查找根字符串
    游标的使用——mysql
    .NET 各种框架
    xml与datatable类型互换
  • 原文地址:https://www.cnblogs.com/fillim/p/4864448.html
Copyright © 2020-2023  润新知