mysql中nullify_mongoengine简单使用

创建model

classUser(Document):

email= StringField(required=True)

first_name= StringField(max_length=50)

last_name= StringField(max_length=50)

文档都是继承Document类。

预留:

字段类型:

StringField,字符串。

ListField,列表。列表里还可以传入字段规定列表内的字段类型,例如ListField(StringField(max_length=30))

ReferenceField, 这是一个保存相关文档的filed

StringFiled(regex=None,max_length=None,min_lenght=None) #字符串类型

IntField(min_value=None,max_value=None) #整数类型

FloatField(min_value=None,max_value=None) #字符串类型

BooleanField() #布尔类型

DateTimeField() #时间类型

listField() #可以插入列表的

DictField() #字典类型

ReferenceField() #参照类型

SequenceField() #自动产生一个数列、 递增的

字段限制:

required,必须的。

max_length,最大长度。

default #默认值 也可以是一个函数 可调用类型

primary_key #插入数据是否重复

null #赋值是否可以为空

choices #列表的范围

unique #当前field只能是唯一的

继承model

classPost(Document):

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

author=ReferenceField(User)

meta= {'allow_inheritance': True}classTextPost(Post):

content=StringField()classImagePost(Post):

image_path=StringField()classLinkPost(Post):

link_url= StringField()

只需要再父类的meta的 'allow_inheritance' 设置为True

内嵌文档

一篇文章post内的所有评论comments直接嵌入这篇文章的内部是mongodb常见的思路,首先创建一个comments的model:

classComment(EmbeddedDocument):

content=StringField()

name= StringField(max_length=120)

这个model继承了EmbeddedDocument类,声明了他就是一个内嵌的文档,它不会在数据库里有个专门的文档保存,例如post这样的文档。post的model应该这样写:

classPost(Document):

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

author=ReferenceField(User)

tags= ListField(StringField(max_length=30))

comments= ListField(EmbeddedDocumentField(Comment))

关联删除

ReferenceField这个字段似乎是一个外键,创建model是指定reverse_delete_rule的值,可以设定关联删除的规则,如:

classPost(Document):

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

author= ReferenceField(User, reverse_delete_rule=CASCADE)

tags= ListField(StringField(max_length=30))

comments= ListField(EmbeddedDocumentField(Comment))

此例中reverse_delete_rule的值设定为CASCADE,这样如果删除了一个用户,用户下所有的关联的post都会被删除。更多字段查询ReferenceField API

添加数据

现在我们可以添加数据了,写法有两种。如:

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

再如:

ross = User(email='ross@example.com')

ross.first_name= 'Ross'ross.last_name= 'Lawley'ross.save()

以上两种都是可以的。注意它可以用属性赋值的语法。如果save()了之后,又修改了属性,再save()就可以了,非常方便。

使用数据

添加几个数据之后,我们可以来使用这些数据了。所有的model,例如上面的Post,User,都有一个objects属性,可以检索出此类下所有的文档。例如我们用继承自Post类的TextPost做个最简单的示范。

for post inTextPost.objects:

print post.content

这样会print出所有属于TextPost的文档的content。如果用Post.objects,可以得到所有属于Post或者继承自Post的model实例化的文档,这是一个QuerySet对象,(类似一个游标对象,不知道对不对)。如:

for post inPost.objects:

print post.title

print'=' *len(post.title)ifisinstance(post, TextPost):

print post.contentifisinstance(post, LinkPost):

print'Link:', post.link_url

可见objects的类是不一样的,只是父类都是Post。

检索指定字段的值的文档也很方便,例:

for post in Post.objects(tags='mongodb'):

print post.title

这样就能检索出tags里有'mongodb'的文档。我觉得很方便,普通的查询条件如name='foo'这样的写法很正常,但tags是一个列表,用这样的写法,直接给个值他就能自己遍历判断是否是列表里的一个值,隐去了列表这个细节,很赞。

objects对象和sqlAlchemy的游标一样,也可以调用first()或者count(),意思都是一样。如:

num_posts = Post.objects(tags='mongodb').count()

print'Found %d posts with tag "mongodb"' % num_posts

连接数据库

mongoengine连接数据可也很方便,最简单的传入数据库名如:

connect还接收, name(数据库名),username,password,host等参数。

配置多个数据库

新建model的时候可以指定model可以属于哪个数据库,可以都添加进来例:

classUser(Document):

name=StringField()

meta= {"db_alias": "user-db"} # 根据元属性确认哪一个数据库classBook(Document):

name=StringField()

meta= {"db_alias": "book-db"}# 根据元属性确认哪一个数据库

classAuthorBooks(Document):

author=ReferenceField(User)

book=ReferenceField(Book)

meta= {"db_alias": "users-books-db"} # 根据元属性确认哪一个数据库

不过这些数据库先要用connet连接。

临时转换数据库database(未知,没用过)

model表虽然设计了存储的数据库,但是有些数据需要存储到另一个数据库怎么办。可以转换:

frommongoengine.context_managers import switch_dbclassUser(Document):

name=StringField()

meta= {"db_alias": "user-db"}

with switch_db(User,'archive-user-db') asUser:

User(name="Ross").save() # Saves the 'archive-user-db'

这样,应该默认保存在“user-db”这个数据库里的User,现在是作为“archive-user-db”的User保存了。这是跨db的保存。

临时转换集合collection

同样mongoegnine也支持collection的转换, 如:

frommongoengine.context_managers import switch_collectionclassGroup(Document):

name=StringField()

Group(name="test").save() # Saves in the defaultdb

with switch_collection(Group,'group2000') asGroup:

Group(name="hello Group 2000 collection!").save() # Saves in group2000 collection

保存到里一个集合,第一个参数为需要转换的model,第二个为目标集合名,最后的model名可以不变。

Reference fields

这是一个设置相关document的fields,如:

classUser(Document):

name=StringField()classPage(Document):

content=StringField()

author=ReferenceField(User)

john= User(name="John Smith")

john.save()

post= Page(content="Test Page")

post.author=john

post.save()

这样就可以引用了。

一对多关系

可以用ListField保存ReferenceField的方法来保存一对多的关系。例:

classUser(Document):

name=StringField()classPage(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])

# Remove Bobfrom the authors fora page.

Page.objects(id='...').update_one(pull__authors=bob)

# Add John to the authorsfora page.

Page.objects(id='...').update_one(push__authors=john)

一次插入和删除一条关联可见最后两行,多个的方法还不知道。

如果关联的文档发生了变化,如何同步改变呢?例如ReferenceField在子级的多对一,一对一关系,如何能删除了关联的父级,子级也一并删除呢?

classParent(Document):

name=StringField()classChild(Document):

name=StringField()

parent= ReferenceField(Parent, reverse_delete_rule=CASCADE)

定义一个反向删除的规则,CASCADE,就能一并删除了。

其实用这样的多对一的方式做到一对多并不方便,这个应用场景更多是一对一的关联。那如何方便的一对多呢。ListField:

classChild(Document):

name=StringField()classParent(Document):

name=StringField()

child= ListField(ReferenceField(Child, reverse_delete_rule=PULL))

首先子级要先定义,应为父级的ReferenceField要传入子级的类。父级定义一个列表保存所有子级ReferenceField。反向删除规则为PULL,这样删除一个child,他的关联就会自动从父级的ListField中删掉了。

另外还有DO_NOTHING,DENY,NULLIFY。

另外GenericReferenceField不需要传入关联类,可以任意指定。

文档名

这个库默认保存的文档是定义的类的缩写加下划线,可以用meta = {'collection': 'YourDocument'}来设置你想要的文档名称

限制文档数量和大小

如果需要限制一个文档的数量或者大小,可以用meta = {'max_documents': 1000, 'max_size': 2000000}

排序

再meta中放入ordering,可以指定文档的默认排序方式,例如meta = {'ordering': ['-published_date']},不过order_by()方法的优先级更高。

clean方法

文档调用save()时,如果定义了clean,会先调用clean,如:

classEssay(Document):

status= StringField(choices=('Published', 'Draft'), required=True)

pub_date=DateTimeField()

def clean(self):"""Ensures that only published essays have a `pub_date` and

automatically sets the pub_date if published and not set""" if self.status == 'Draft' and self.pub_date isnot None:

msg= 'Draft entries should not have a publication date.'raise ValidationError(msg)

# Set the pub_datefor published items if not set.if self.status == 'Published' and self.pub_date isNone:

self.pub_date= datetime.now()

检索

操作符

ne – not equal to,不等于

lt – less than,小于

lte – less than or equal to,小于或等于

gt – greater than,大于

gte – greater than or equal to,大于或等于

not – negate a standard check, may be used before other operators (e.g. Q(age__not__mod=5)),否,与其他操作符一起用in – value is inlist (a list of values should be provided),提供一个列表,数据库值在列表内

nin – valueis not inlist (a list of values should be provided),提供一个列表,数据库值不在列表内

mod – value% x == y, wherex and y are two provided values,整除

all – every itemin list of values provided is inarray,提供的列表元素都在数据库数组内

size – the size of the arrayis,数据库数组的大小

exists – valuefor field exists,field存在

字符串检索

exact – stringfield exactly matches value,完全匹配

iexact –string field exactly matches value (caseinsensitive),完全匹配,不区分大小写

contains –stringfield contains value,包含

icontains –string field contains value (caseinsensitive),包含,不区分大小写

startswith –stringfield starts with value,开始于

istartswith –string field starts with value (caseinsensitive),开始于,不区分大小写

endswith –stringfield ends with value,结束于

iendswith –string field ends with value (caseinsensitive),结束于,不区分大小写

match – performs an $elemMatch so you can match an entire document within an array,匹配?

列表检索

如果一个域是个列表,同样可以传入一个元素,这样做的意思是检索所有这个列表域中包含这个元素的文档,例:

classPage(Document):

tags=ListField(StringField())

# This will match all pages that have the word'coding' as an item inthe

#'tags'list

Page.objects(tags='coding')

当然也可以指定这个列表域的序号来匹配,如:

Page.objects(tags__0='db')

这样即是匹配列表域第一个元素为‘db’的文档

如果对列表检索的内的结果需要分割,可如:

# comments - skip 5, limit 10Page.objects.fields(slice__comments=[5, 10])

检索结果的分割和限制

可以使用limit()和skip()方法,但是比较好的是:

# Only the first 5people

users= User.objects[:5]

# All exceptfor the first 5people

users= User.objects[5:]

#5 users, starting fromthe 11th user found

users= User.objects[10:15]

定义默认的搜索条件

可以定义自己的object方法:

classBlogPost(Document):

title=StringField()

date=DateTimeField()

@queryset_manager

def objects(doc_cls, queryset):

# This may actually also be done by defining adefault ordering for# the document, butthisillustrates the use of manager methodsreturn queryset.order_by('-date')

这样可行,但是也别闲着没事干去改默认的函数,还是自己定义一个吧:

classBlogPost(Document):

title=StringField()

published=BooleanField()

@queryset_manager

def live_posts(doc_cls, queryset):return queryset.filter(published=True)

BlogPost(title='test1', published=False).save()

BlogPost(title='test2', published=True).save()

assert len(BlogPost.objects)== 2assert len(BlogPost.live_posts())== 1

聚合

计算一个域的总和,使用sum():

yearly_expense = Employee.objects.sum('salary')

计算一个域的平均值,使用average():

mean_age = User.objects.average('age')

使用only()提高检索效率

使用only()只会得到文档中的某个域,以及是默认值的域,如:

classFilm(Document):

title=StringField()

year=IntField()

rating= IntField(default=3)

Film(title='The Shawshank Redemption', year=1994, rating=5).save()

f= Film.objects.only('title').first()

f.title #'The Shawshank Redemption'f.year # None

f.rating #default value 3

exclude()是和它相反的方法。

另外,如果用了only(),之后有需要其他的值了,可以使用reload()

原子更新

可以使用update_one(), update() 和 modify() 方法对 QuerySet 进行更新,和使用modify() 和 save() 对一个文档进行更新。下面是一些搭配使用的修改符:

set – seta particular value,设置某个值

unset – delete a particular value (since MongoDB v1.3),删除某个值

inc – increment a value by a given amount,增加

dec – decrement a value by a given amount,减少

push – append a value to a list,增加列表一个值

push_all – append several values to a list,增加列表多个值(传入一个列表)

pop – remove the first or last element of a list depending on the value,取出一个列表最前或最后的值

pull – remove a valuefroma list,删除一个列表的值

pull_all – remove several valuesfroma list,删除一个列表多个值

add_to_set – add value to a list onlyif its not in the list already,加入列表一个值,如果它之前不在其中。

这些修改符和检索操作符用法差不多,只是他们在域名之前:

post = BlogPost(title='Test', page_views=0, tags=['database'])

post.save()

BlogPost.objects(id=post.id).update_one(inc__page_views=1)

post.reload() # the document has been changed, so we need to reload it

post.page_views #1BlogPost.objects(id=post.id).update_one(set__title='Example Post')

post.reload()

post.title #'Example Post'BlogPost.objects(id=post.id).update_one(push__tags='nosql')

post.reload()

post.tags # ['database', 'nosql']

如果没有指定修改符,那么默认是set,所以以下两句实际是相同的:

BlogPost.objects(id=post.id).update(title='Example Post')

BlogPost.objects(id=post.id).update(set__title='Example Post')

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值