Skip to content

Commit 3bb7b96

Browse files
committed
queryset extension comes here
1 parent cca2a32 commit 3bb7b96

File tree

5 files changed

+76
-18
lines changed

5 files changed

+76
-18
lines changed

flask_mongoengine/__init__.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66

77
import mongoengine
88

9-
from mongoengine.queryset import MultipleObjectsReturned, DoesNotExist, QuerySet
9+
from mongoengine.queryset import (
10+
MultipleObjectsReturned, DoesNotExist, QuerySet
11+
)
1012
from mongoengine.base import ValidationError
1113

1214
from pymongo import uri_parser
1315

14-
from .sessions import *
15-
from .pagination import *
16+
from .sessions import * # noqa
17+
from .pagination import * # noqa
1618
from .json import overide_json_encoder
1719
from .wtf import WtfBaseField
1820

@@ -87,7 +89,6 @@ def _create_connection(conn_settings):
8789
return mongoengine.connect(conn.pop('db', 'test'), **conn)
8890

8991

90-
9192
class MongoEngine(object):
9293

9394
def __init__(self, app=None, config=None):
@@ -106,7 +107,7 @@ def init_app(self, app, config=None):
106107
# Make documents JSON serializable
107108
overide_json_encoder(app)
108109

109-
if not 'mongoengine' in app.extensions:
110+
if 'mongoengine' not in app.extensions:
110111
app.extensions['mongoengine'] = {}
111112

112113
if self in app.extensions['mongoengine']:
@@ -147,6 +148,46 @@ class BaseQuerySet(QuerySet):
147148
A base queryset with handy extras
148149
"""
149150

151+
def get_or_create(self, write_options=None, auto_save=True,
152+
*q_objs, **query):
153+
"""Retrieve unique object or create, if it doesn't exist. Returns a
154+
tuple of ``(object, created)``, where ``object`` is the retrieved or
155+
created object and ``created`` is a boolean specifying whether a new
156+
object was created. Raises
157+
:class:`~mongoengine.queryset.MultipleObjectsReturned` or
158+
`DocumentName.MultipleObjectsReturned` if multiple results are found.
159+
A new document will be created if the document doesn't exists; a
160+
dictionary of default values for the new document may be provided as a
161+
keyword argument called :attr:`defaults`.
162+
.. note:: This requires two separate operations and therefore a
163+
race condition exists. Because there are no transactions in
164+
mongoDB other approaches should be investigated, to ensure you
165+
don't accidently duplicate data when using this method. This is
166+
now scheduled to be removed before 1.0
167+
:param write_options: optional extra keyword arguments used if we
168+
have to create a new document.
169+
Passes any write_options onto :meth:`~mongoengine.Document.save`
170+
:param auto_save: if the object is to be saved automatically if
171+
not found.
172+
173+
add to your documents:
174+
meta = {'queryset_class': ExtendedQuerySet}
175+
"""
176+
defaults = query.get('defaults', {})
177+
if 'defaults' in query:
178+
del query['defaults']
179+
180+
try:
181+
doc = self.get(*q_objs, **query)
182+
return doc, False
183+
except self._document.DoesNotExist:
184+
query.update(defaults)
185+
doc = self._document(**query)
186+
187+
if auto_save:
188+
doc.save(write_options=write_options)
189+
return doc, True
190+
150191
def get_or_404(self, *args, **kwargs):
151192
try:
152193
return self.get(*args, **kwargs)

flask_mongoengine/json.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
from mongoengine.base import BaseDocument
44
try:
55
from mongoengine.base import BaseQuerySet
6-
except ImportError as ie: # support mongoengine < 0.7
6+
except ImportError as ie: # support mongoengine < 0.7
77
from mongoengine.queryset import QuerySet as BaseQuerySet
88

9+
910
def _make_encoder(superclass):
1011
class MongoEngineJSONEncoder(superclass):
1112
'''

flask_mongoengine/operation_tracker.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
removes = []
3636
response_sizes = []
3737

38+
3839
# Wrap helpers._unpack_response for getting response size
3940
@functools.wraps(_original_methods['_unpack_response'])
4041
def _unpack_response(response, *args, **kwargs):
@@ -47,6 +48,7 @@ def _unpack_response(response, *args, **kwargs):
4748
response_sizes.append(sys.getsizeof(response) / 1024.0)
4849
return result
4950

51+
5052
# Wrap Cursor.insert for getting queries
5153
@functools.wraps(_original_methods['insert'])
5254
def _insert(collection_self, doc_or_docs, manipulate=True,
@@ -61,7 +63,7 @@ def _insert(collection_self, doc_or_docs, manipulate=True,
6163
)
6264
total_time = (time.time() - start_time) * 1000
6365

64-
__traceback_hide__ = True
66+
__traceback_hide__ = True # noqa
6567
stack_trace, internal = _tidy_stacktrace()
6668
inserts.append({
6769
'document': doc_or_docs,
@@ -73,6 +75,7 @@ def _insert(collection_self, doc_or_docs, manipulate=True,
7375
})
7476
return result
7577

78+
7679
# Wrap Cursor.update for getting queries
7780
@functools.wraps(_original_methods['update'])
7881
def _update(collection_self, spec, document, upsert=False,
@@ -89,7 +92,7 @@ def _update(collection_self, spec, document, upsert=False,
8992
)
9093
total_time = (time.time() - start_time) * 1000
9194

92-
__traceback_hide__ = True
95+
__traceback_hide__ = True # noqa
9396
stack_trace, internal = _tidy_stacktrace()
9497
updates.append({
9598
'document': document,
@@ -104,6 +107,7 @@ def _update(collection_self, spec, document, upsert=False,
104107
})
105108
return result
106109

110+
107111
# Wrap Cursor.remove for getting queries
108112
@functools.wraps(_original_methods['remove'])
109113
def _remove(collection_self, spec_or_id, safe=None, **kwargs):
@@ -116,7 +120,7 @@ def _remove(collection_self, spec_or_id, safe=None, **kwargs):
116120
)
117121
total_time = (time.time() - start_time) * 1000
118122

119-
__traceback_hide__ = True
123+
__traceback_hide__ = True # noqa
120124
stack_trace, internal = _tidy_stacktrace()
121125
removes.append({
122126
'spec_or_id': spec_or_id,
@@ -128,6 +132,7 @@ def _remove(collection_self, spec_or_id, safe=None, **kwargs):
128132
})
129133
return result
130134

135+
131136
# Wrap Cursor._refresh for getting queries
132137
@functools.wraps(_original_methods['refresh'])
133138
def _cursor_refresh(cursor_self):
@@ -169,11 +174,11 @@ def privar(name):
169174
if snapshot:
170175
query_son["$snapshot"] = snapshot
171176

172-
maxScan = privar("max_scan")
177+
maxScan = privar("max_scan") # noqa
173178
if maxScan:
174179
query_son["$maxScan"] = maxScan
175180

176-
__traceback_hide__ = True
181+
__traceback_hide__ = True # noqa
177182
stack_trace, internal = _tidy_stacktrace()
178183
query_data = {
179184
'time': total_time,
@@ -209,6 +214,7 @@ def privar(name):
209214

210215
return result
211216

217+
212218
def install_tracker():
213219
if pymongo.collection.Collection.insert != _insert:
214220
pymongo.collection.Collection.insert = _insert
@@ -221,6 +227,7 @@ def install_tracker():
221227
if pymongo.helpers._unpack_response != _unpack_response:
222228
pymongo.helpers._unpack_response = _unpack_response
223229

230+
224231
def uninstall_tracker():
225232
if pymongo.collection.Collection.insert == _insert:
226233
pymongo.collection.Collection.insert = _original_methods['insert']
@@ -231,7 +238,9 @@ def uninstall_tracker():
231238
if pymongo.cursor.Cursor._refresh == _cursor_refresh:
232239
pymongo.cursor.Cursor._refresh = _original_methods['cursor_refresh']
233240
if pymongo.helpers._unpack_response == _unpack_response:
234-
pymongo.helpers._unpack_response = _original_methods['_unpack_response']
241+
pymongo.helpers._unpack_response = _original_methods[
242+
'_unpack_response']
243+
235244

236245
def reset():
237246
global queries, inserts, updates, removes, response_sizes
@@ -241,6 +250,7 @@ def reset():
241250
removes = []
242251
response_sizes = []
243252

253+
244254
def _get_ordering(son):
245255
"""Helper function to extract formatted ordering from dict.
246256
"""
@@ -250,11 +260,13 @@ def fmt(field, direction):
250260
if '$orderby' in son:
251261
return ', '.join(fmt(f, d) for f, d in son['$orderby'].items())
252262

263+
253264
def _tidy_stacktrace():
254265
"""
255266
Tidy the stack_trace
256267
"""
257-
socketserver_path = os.path.realpath(os.path.dirname(SocketServer.__file__))
268+
socketserver_path = os.path.realpath(
269+
os.path.dirname(SocketServer.__file__))
258270
pymongo_path = os.path.realpath(os.path.dirname(pymongo.__file__))
259271
paths = ['/site-packages/', '/flaskext/', socketserver_path, pymongo_path]
260272
internal = False

flask_mongoengine/panels.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ def nav_title(self):
4141

4242
def nav_subtitle(self):
4343
attrs = ['queries', 'inserts', 'updates', 'removes']
44-
ops = sum(sum((1 for o in getattr(operation_tracker, a)
45-
if not o['internal']))
46-
for a in attrs)
44+
ops = sum(
45+
sum(
46+
(1 for o in getattr(operation_tracker, a)
47+
if not o['internal']))
48+
for a in attrs
49+
)
4750
total_time = sum(sum(o['time'] for o in getattr(operation_tracker, a))
4851
for a in attrs)
4952
return '{0} operations in {1:.2f}ms'.format(ops, total_time)
@@ -60,5 +63,6 @@ def content(self):
6063
context['inserts'] = operation_tracker.inserts
6164
context['updates'] = operation_tracker.updates
6265
context['removes'] = operation_tracker.removes
63-
context['slow_query_limit'] = current_app.config.get('MONGO_DEBUG_PANEL_SLOW_QUERY_LIMIT', 100)
66+
context['slow_query_limit'] = current_app.config.get(
67+
'MONGO_DEBUG_PANEL_SLOW_QUERY_LIMIT', 100)
6468
return self.render('panels/mongo-panel.html', context)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
setup(
2626
name='quokka-flask-mongoengine',
27-
version='0.7.2',
27+
version='0.7.3',
2828
url='https://github.com/mongoengine/flask-mongoengine',
2929
license='BSD',
3030
author='Ross Lawley',

0 commit comments

Comments
 (0)