MongoDB3 mongoengine(基本使用, 聯合唯一, ReferenceField, EmbeddedDocument, 時間段查詢)


文章參考:https://blog.csdn.net/xc_zhou/article/details/80837962

 

mongoengine

簡介

pymongo來操作MongoDB數據庫,但是直接把對於數據庫的操作代碼都寫在腳本中,這會讓應用的代碼耦合性太強,而且不利於代碼的優化管理

一般應用都是使用MVC框架來設計的,為了更好地維持MVC結構,需要把數據庫操作部分作為model抽離出來,這就需要借助MongoEngine

MongoEngine是一個對象文檔映射器(ODM),相當於一個基於SQL的對象關系映射器(ORM)

MongoEngine提供的抽象是基於類的,創建的所有模型都是類

 

1基本使用

#pip install mongoengine    # 安裝

from mongoengine import *
connect('test', host='localhost', port=27017)
import datetime
class Users(Document):
    name = StringField(required=True, max_length=200)  # 插入任意數據,mongo庫會產生該唯一索引,如要改成聯合索引,先到表中刪了該唯一索引
    age = IntField(required=True)

users = Users.objects.all() #返回所有的文檔對象列表
for u in users:
    print("name:",u.name,",age:",u.age)

 保存文檔

from mongoengine import *
connect('test',host='localhost',port=27017)
class Users(Document):
    name = StringField(required=True,max_length=200)
    age = IntField(required=True)
user1 = Users(
    name='zz',
    age=11
)
user1.save()
print(user1.name)   # zz
user1.name = 'zz11'
user1.save()    # 保存后,age還是11
print(user1.name)   # zz11

 查詢10=<年齡<30的,按姓名排列

from mongoengine import *
connect('test', host='localhost', port=27017)
import datetime
class Users(Document):
    name = StringField(required=True, max_length=200)
    age = IntField(required=True)
user_search = Users.objects(age__gte=10, age__lt=33).order_by('name')
for u in user_search:
    print("name:",u.name,",age:",u.age)

查詢10=<年齡<30的,按姓名倒序

from mongoengine import *
connect('test', host='localhost', port=27017)
import datetime
class Users(Document):
    name = StringField(required=True, max_length=200)
    age = IntField(required=True)
user_search = Users.objects(age__gte=10, age__lt=33).order_by('-name')
for u in user_search:
    print("name:",u.name,",age:",u.age)

查詢name=zz11

from mongoengine import *
connect('test', host='localhost', port=27017)
import datetime
class Users(Document):
    name = StringField(required=True, max_length=200)
    age = IntField(required=True)

tmp = Users.objects(name="zz11")
for u in tmp:
    print("name:",u.name,",age:",u.age)

修改name=zz11的age加1

from mongoengine import *
connect('test', host='localhost', port=27017)
import datetime
class Users(Document):
    name = StringField(required=True, max_length=200)
    age = IntField(required=True)
tmp = Users.objects(name="zz11").update(inc__age=1)
tmp = Users.objects(name="zz11")
for u in tmp:
    print("name:",u.name,",age:",u.age)

修改name=zz11的age設為55

from mongoengine import *
connect('test', host='localhost', port=27017)
import datetime
class Users(Document):
    name = StringField(required=True, max_length=200)
    age = IntField(required=True)

tmp = Users.objects(name="zz11").update(set__age=55)
tmp = Users.objects(name="zz11")
for u in tmp:
    print("name:",u.name,",age:",u.age)

 

聯合唯一

class Publisher(Document):
    """
    用於存入發布賬號
    """
    source = fields.StringField(verbose_name='來源',blank=True, null=True)
    column = fields.StringField(default="", verbose_name='欄目',blank=True, null=True)
    publisher = fields.StringField(verbose_name='用戶姓名')
    user_code = fields.StringField(unique_with=["source","column"],verbose_name='用戶id') # 發布者id,來源,欄目 三者聯合唯一 
  (一但有數據插入庫,mongo表中就會創建該聯合唯一索引,后續修改先刪索引)
meta = {'collection':'publisher_info','strict': False}

 

2mongoengine基本用法實例:

from mongoengine import *
from datetime import datetime

#連接數據庫:test
connect('test', host='localhost', port=27017)    # 連接本地test數據庫
# connect('test', host='127.0.0.1', port=27017, username='test', password='test')

# Defining our documents
# 定義文檔user,post,對應集合user,post
class User(Document):
    # required為True則必須賦予初始值
    email = StringField(required=True)
    first_name = StringField(max_length=50)
    last_name = StringField(max_length=50)
    date = DateTimeField(default=datetime.now(), required=True)

# Embedded documents,it doesn’t have its own collection in the database
class Comment(EmbeddedDocument):    # 嵌入文檔,用於嵌入在其他文檔EmbeddedDocumentField字段中
    content = StringField()
    name = StringField(max_length=120)

class Post(Document):
    title = StringField(max_length=120, required=True)
    # ReferenceField相當於foreign key
    author = ReferenceField(User)    # 通過引用字段可以通過文檔直接獲取引用字段引用的那個文檔
    tags = ListField(StringField(max_length=30))
    comments = ListField(EmbeddedDocumentField(Comment))
    # 允許繼承
    meta = {'allow_inheritance': True}

class TextPost(Post):
    content = StringField()

class ImagePost(Post):
    image_path = StringField()

class LinkPost(Post):
    link_url = StringField()

# Dynamic document schemas:DynamicDocument documents work in the same way as Document but any data / attributes set to them will also be saved
class Page(DynamicDocument): # 動態文檔和普通文檔一樣,當有定義外的多余字段都能被保存
    title = StringField(max_length=200, required=True)
    date_modified = DateTimeField(default=datetime.now())

添加數據

john = User(email='john@example.com', first_name='John', last_name='Tao').save()
ross = User(email='ross@example.com')
ross.first_name = 'Ross'
ross.last_name = 'Lawley'
ross.save()

comment1 = Comment(content='Good work!',name = 'LindenTao') #不會創建對應集合。
comment2 = Comment(content='Nice article!')
post0 = Post(title = 'post0',tags = ['post_0_tag'])
post0.comments = [comment1,comment2]
post0.save()    # 會多出_cls字段為Post,因為允許繼承繼承,_cls會標識出對象所屬的類

post1 = TextPost(title='Fun with MongoEngine', author=john)       # john必須保存后才能用  john.save()
post1.content = 'Took a look at MongoEngine today, looks pretty cool.'
post1.tags = ['mongodb', 'mongoengine']
post1.save()    # 保存於post集合下,author字段為對象ObjectId("5fd8d55b353560e1260a451e")

post2 = LinkPost(title='MongoEngine Documentation', author=ross)    # ross必須保存后才能用  ross.save()
post2.link_url = 'http://docs.mongoengine.com/'
post2.tags = ['mongoengine']
post2.save()  # _cls字段為Post.LinkPost

# 創建一個page集合,並且添加一個tags字段
page = Page(title='Using MongoEngine')
page.tags = ['mongodb', 'mongoengine']
page.save()

創建了三個集合:user,post,page

查看數據

# 查看數據
for post in Post.objects:
    print post.title
    print '=' * len(post.title)

    if isinstance(post, TextPost):
        print post.content

    if isinstance(post, LinkPost):
        print 'Link:', post.link_url

# 通過引用字段直接獲取引用文檔對象    
for post in TextPost.objects:
    print post.content
    print post.author.email  
au = TextPost.objects.all().first().author
print au.email

# 通過標簽查詢    
for post in Post.objects(tags='mongodb'):
    print post.title   
num_posts = Post.objects(tags='mongodb').count()
print 'Found %d posts with tag "mongodb"' % num_posts

# 多條件查詢(導入Q類) 
User.objects((Q(country='uk') & Q(age__gte=18)) | Q(age__gte=20))   

# 更新文檔
ross = User.objects(first_name = 'Ross')  # 所有first_name為Ross的對象
# ross = User.objects.filter(first_name = 'John')    # 所有first_name為Ross的對象   和上面作用相同
ross.update(date = datetime.now()) 
User.objects(first_name='John').update(set__email='123456@qq.com')
//對 lorem 添加商品圖片信息
lorempic = GoodsPic(name='l2.jpg', path='/static/images/l2.jpg')
lorem = Goods.objects(id='575d38e336dc6a55d048f35f')
lorem.update_one(push__pic=lorempic)
# 刪除文檔
ross.delete() # 刪除所有ross對象

 

3基本使用

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)

插入

cate = Categories(name="Linux")   # 如果required為True則必須賦予初始值,如果有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 Tags(EmbeddedDocument):  # 定義Tags嵌入文檔類
    name = StringField()
    date = DateTimeField(default=datetime.now())

class Posts(Document):
    title = StringField(max_length=100, required=True)
    content = StringField(required=True)
    tags = ListField(EmbeddedDocumentField('Tags'),required=True)   # Tags要定義在此類上方
    categories = ReferenceField(Categories)

插入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)
start = datetime(2020, 11, 1)
end = datetime(2020, 12, 18)
# tags__date tags字段下的date字段
articles = Posts.objects(tags__date__gte=start, tags__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’}) 使用i n c 和 inc和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")

 

高級用法參考:https://blog.csdn.net/weixin_42042680/article/details/87909424


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM