文章參考: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