0
# MongoEngine Integration
1
2
MongoDB document administration through MongoEngine ORM integration with embedded documents, NoSQL-specific features, and flexible document structures.
3
4
## Capabilities
5
6
### MongoEngine Model View
7
8
Main model view class for MongoEngine documents with CRUD operations, embedded document handling, and MongoDB-specific querying.
9
10
```python { .api }
11
from flask_admin.contrib.mongoengine import ModelView
12
13
class ModelView(BaseModelView):
14
def __init__(self, model, name=None, category=None, endpoint=None, url=None, **kwargs):
15
"""
16
Initialize MongoEngine model view.
17
18
Args:
19
model: MongoEngine document class
20
name (str, optional): View name for menu
21
category (str, optional): Menu category
22
endpoint (str, optional): Blueprint endpoint
23
url (str, optional): URL prefix
24
**kwargs: Additional view configuration
25
"""
26
27
# MongoEngine-specific configuration
28
subdocuments = {} # Embedded document configuration
29
embedded_list_columns = [] # Columns for embedded lists
30
31
# MongoDB querying
32
def get_query(self):
33
"""
34
Get base QuerySet for list view.
35
36
Returns:
37
QuerySet: MongoEngine QuerySet object
38
"""
39
40
def get_list(self, page, sort_column, sort_desc, search, filters, execute=True, page_size=None):
41
"""
42
Get paginated document list with sorting, searching, and filtering.
43
44
Args:
45
page (int): Page number (0-based)
46
sort_column (str): Field to sort by
47
sort_desc (bool): Sort in descending order
48
search (str): Search query string
49
filters (list): Active filter list
50
execute (bool): Execute query immediately
51
page_size (int, optional): Items per page
52
53
Returns:
54
tuple: (total_count, items) if execute=True, queryset if execute=False
55
"""
56
57
def get_one(self, id):
58
"""
59
Get single document instance by ObjectId.
60
61
Args:
62
id (str): Document ObjectId as string
63
64
Returns:
65
Document instance or None if not found
66
"""
67
68
# CRUD operations for documents
69
def create_model(self, form):
70
"""
71
Create new document instance from form data.
72
73
Args:
74
form: Validated form instance
75
76
Returns:
77
bool: True if creation successful
78
"""
79
80
def update_model(self, form, model):
81
"""
82
Update existing document instance from form data.
83
84
Args:
85
form: Validated form instance
86
model: Document instance to update
87
88
Returns:
89
bool: True if update successful
90
"""
91
92
def delete_model(self, model):
93
"""
94
Delete document instance.
95
96
Args:
97
model: Document instance to delete
98
99
Returns:
100
bool: True if deletion successful
101
"""
102
103
# Form scaffolding for MongoEngine
104
def scaffold_form(self):
105
"""
106
Auto-generate form class from MongoEngine document.
107
108
Returns:
109
Form class with fields for document fields
110
"""
111
112
def scaffold_list_form(self, widget=None, validators=None):
113
"""
114
Generate form for inline list editing.
115
116
Args:
117
widget: Custom widget for fields
118
validators: Custom validators
119
120
Returns:
121
Form class for inline editing
122
"""
123
124
def scaffold_filters(self, name):
125
"""
126
Generate filters for document field.
127
128
Args:
129
name (str): Field name
130
131
Returns:
132
list: Available filter types for field
133
"""
134
135
# MongoDB-specific methods
136
def get_pk_value(self, model):
137
"""
138
Get primary key (ObjectId) from document instance.
139
140
Args:
141
model: Document instance
142
143
Returns:
144
str: ObjectId as string
145
"""
146
147
def apply_search(self, query, search):
148
"""
149
Apply text search filters to QuerySet.
150
151
Args:
152
query: Base QuerySet
153
search (str): Search string
154
155
Returns:
156
QuerySet: QuerySet with search filters applied
157
"""
158
159
def apply_filters(self, query, filters):
160
"""
161
Apply field filters to QuerySet.
162
163
Args:
164
query: Base QuerySet
165
filters (list): Active filters
166
167
Returns:
168
QuerySet: QuerySet with filters applied
169
"""
170
171
def apply_sorting(self, query, sort_field, sort_desc):
172
"""
173
Apply sorting to QuerySet.
174
175
Args:
176
query: Base QuerySet
177
sort_field (str): Field to sort by
178
sort_desc (bool): Sort descending
179
180
Returns:
181
QuerySet: Sorted QuerySet
182
"""
183
```
184
185
### Embedded Document Forms
186
187
Support for editing embedded documents within parent document forms.
188
189
```python { .api }
190
class EmbeddedForm:
191
def __init__(
192
self,
193
form_base_class=None,
194
form_columns=None,
195
excluded_form_columns=None,
196
form_args=None,
197
form_widget_args=None,
198
form_overrides=None
199
):
200
"""
201
Initialize embedded document form configuration.
202
203
Args:
204
form_base_class: Base form class for embedded form
205
form_columns (list, optional): Fields to include in embedded form
206
excluded_form_columns (list, optional): Fields to exclude
207
form_args (dict, optional): Form field arguments
208
form_widget_args (dict, optional): Widget arguments
209
form_overrides (dict, optional): Field type overrides
210
"""
211
```
212
213
## Usage Examples
214
215
### Basic MongoEngine Model View
216
217
```python
218
from flask import Flask
219
from flask_mongoengine import MongoEngine
220
from flask_admin import Admin
221
from flask_admin.contrib.mongoengine import ModelView
222
from mongoengine import Document, EmbeddedDocument, fields
223
from datetime import datetime
224
225
app = Flask(__name__)
226
app.config['MONGODB_SETTINGS'] = {
227
'db': 'blog',
228
'host': 'localhost',
229
'port': 27017
230
}
231
app.config['SECRET_KEY'] = 'secret-key'
232
233
db = MongoEngine(app)
234
235
# Define documents
236
class User(Document):
237
username = fields.StringField(max_length=80, unique=True, required=True)
238
email = fields.EmailField(required=True)
239
created_at = fields.DateTimeField(default=datetime.utcnow)
240
is_active = fields.BooleanField(default=True)
241
profile = fields.EmbeddedDocumentField('UserProfile')
242
243
class UserProfile(EmbeddedDocument):
244
first_name = fields.StringField(max_length=50)
245
last_name = fields.StringField(max_length=50)
246
bio = fields.StringField(max_length=500)
247
avatar_url = fields.URLField()
248
249
class BlogPost(Document):
250
title = fields.StringField(max_length=200, required=True)
251
content = fields.StringField()
252
author = fields.ReferenceField(User, required=True)
253
tags = fields.ListField(fields.StringField(max_length=50))
254
created_at = fields.DateTimeField(default=datetime.utcnow)
255
published = fields.BooleanField(default=False)
256
257
meta = {
258
'indexes': ['title', 'author', 'created_at'],
259
'ordering': ['-created_at']
260
}
261
262
# Create admin views
263
class UserModelView(ModelView):
264
list_columns = ['username', 'email', 'profile.first_name', 'profile.last_name', 'created_at', 'is_active']
265
column_searchable_list = ['username', 'email', 'profile.first_name', 'profile.last_name']
266
column_filters = ['is_active', 'created_at']
267
268
form_subdocuments = {
269
'profile': {
270
'form_columns': ['first_name', 'last_name', 'bio', 'avatar_url']
271
}
272
}
273
274
class BlogPostModelView(ModelView):
275
list_columns = ['title', 'author.username', 'created_at', 'published']
276
column_searchable_list = ['title', 'content', 'author.username']
277
column_filters = ['author', 'published', 'created_at', 'tags']
278
279
form_columns = ['title', 'content', 'author', 'tags', 'published']
280
281
# Initialize admin
282
admin = Admin(app, name='Blog Admin')
283
admin.add_view(UserModelView(User, name='Users'))
284
admin.add_view(BlogPostModelView(BlogPost, name='Blog Posts'))
285
```
286
287
### Embedded Document Handling
288
289
```python
290
from flask_admin.contrib.mongoengine import EmbeddedForm
291
292
class Address(EmbeddedDocument):
293
street = fields.StringField(max_length=200)
294
city = fields.StringField(max_length=100)
295
state = fields.StringField(max_length=50)
296
zip_code = fields.StringField(max_length=20)
297
country = fields.StringField(max_length=50, default='USA')
298
299
class ContactInfo(EmbeddedDocument):
300
phone = fields.StringField(max_length=20)
301
fax = fields.StringField(max_length=20)
302
website = fields.URLField()
303
304
class Company(Document):
305
name = fields.StringField(max_length=200, required=True)
306
address = fields.EmbeddedDocumentField(Address)
307
contact = fields.EmbeddedDocumentField(ContactInfo)
308
employees = fields.ListField(fields.ReferenceField(User))
309
founded = fields.DateTimeField()
310
311
class CompanyModelView(ModelView):
312
# Configure embedded document forms
313
form_subdocuments = {
314
'address': {
315
'form_columns': ['street', 'city', 'state', 'zip_code', 'country'],
316
'form_args': {
317
'country': {'default': 'USA'}
318
}
319
},
320
'contact': {
321
'form_columns': ['phone', 'website'], # Exclude fax
322
'form_widget_args': {
323
'phone': {'placeholder': '+1-555-123-4567'},
324
'website': {'placeholder': 'https://example.com'}
325
}
326
}
327
}
328
329
# Display embedded fields in list
330
list_columns = ['name', 'address.city', 'address.state', 'contact.phone', 'founded']
331
332
column_labels = {
333
'address.city': 'City',
334
'address.state': 'State',
335
'contact.phone': 'Phone'
336
}
337
338
admin.add_view(CompanyModelView(Company, name='Companies'))
339
```
340
341
### Advanced MongoDB Queries and Filtering
342
343
```python
344
from mongoengine import Q
345
from flask_admin.contrib.mongoengine.filters import FilterEqual, FilterLike, FilterInList
346
347
class AdvancedBlogPostView(ModelView):
348
# Text search across multiple fields
349
column_searchable_list = ['title', 'content', 'tags']
350
351
# MongoDB-specific filters
352
column_filters = [
353
'author',
354
'published',
355
'created_at',
356
FilterLike('title', 'Title Contains'),
357
FilterEqual('author', 'Exact Author'),
358
FilterInList('tags', 'Has Tags', options=[
359
('python', 'Python'),
360
('flask', 'Flask'),
361
('mongodb', 'MongoDB')
362
])
363
]
364
365
# Custom query with MongoDB aggregation
366
def get_query(self):
367
# Add complex filters using MongoEngine Q objects
368
return BlogPost.objects.filter(
369
Q(published=True) | Q(author=current_user.id)
370
)
371
372
# Custom search with regex
373
def apply_search(self, query, search):
374
if search:
375
# MongoDB regex search (case-insensitive)
376
search_filter = (
377
Q(title__icontains=search) |
378
Q(content__icontains=search) |
379
Q(tags__in=[search])
380
)
381
query = query.filter(search_filter)
382
return query
383
384
# Custom column formatter for tags
385
def _tags_formatter(view, context, model, name):
386
if model.tags:
387
return ', '.join(model.tags[:3]) # Show first 3 tags
388
return ''
389
390
column_formatters = {
391
'tags': _tags_formatter
392
}
393
```
394
395
### List and Embedded List Fields
396
397
```python
398
class Product(EmbeddedDocument):
399
name = fields.StringField(required=True)
400
price = fields.DecimalField(min_value=0)
401
sku = fields.StringField()
402
403
class Order(Document):
404
order_number = fields.StringField(unique=True, required=True)
405
customer_email = fields.EmailField(required=True)
406
products = fields.ListField(fields.EmbeddedDocumentField(Product))
407
shipping_address = fields.EmbeddedDocumentField(Address)
408
order_date = fields.DateTimeField(default=datetime.utcnow)
409
status = fields.StringField(
410
choices=['pending', 'processing', 'shipped', 'delivered'],
411
default='pending'
412
)
413
414
class OrderModelView(ModelView):
415
# Configure embedded list editing
416
form_subdocuments = {
417
'products': {
418
'form_columns': ['name', 'price', 'sku'],
419
'form_widget_args': {
420
'price': {'step': '0.01', 'min': '0'}
421
}
422
},
423
'shipping_address': {
424
'form_columns': ['street', 'city', 'state', 'zip_code']
425
}
426
}
427
428
list_columns = [
429
'order_number',
430
'customer_email',
431
'products_count',
432
'order_date',
433
'status'
434
]
435
436
# Custom formatter for product count
437
def _products_count_formatter(view, context, model, name):
438
return len(model.products) if model.products else 0
439
440
column_formatters = {
441
'products_count': _products_count_formatter
442
}
443
444
column_labels = {
445
'products_count': 'Items'
446
}
447
448
# Custom form processing
449
def on_model_change(self, form, model, is_created):
450
# Generate order number for new orders
451
if is_created and not model.order_number:
452
import uuid
453
model.order_number = f'ORD-{uuid.uuid4().hex[:8].upper()}'
454
```
455
456
### File Upload with GridFS
457
458
```python
459
from mongoengine import FileField
460
from werkzeug.utils import secure_filename
461
462
class Document(Document):
463
title = fields.StringField(required=True)
464
description = fields.StringField()
465
file = FileField()
466
uploaded_at = fields.DateTimeField(default=datetime.utcnow)
467
uploaded_by = fields.ReferenceField(User)
468
469
class DocumentModelView(ModelView):
470
form_columns = ['title', 'description', 'file']
471
list_columns = ['title', 'file.filename', 'uploaded_at', 'uploaded_by.username']
472
473
column_labels = {
474
'file.filename': 'Filename',
475
'uploaded_by.username': 'Uploaded By'
476
}
477
478
# Custom file formatter
479
def _file_formatter(view, context, model, name):
480
if model.file:
481
return Markup(f'<a href="/download/{model.id}">{model.file.filename}</a>')
482
return ''
483
484
column_formatters = {
485
'file': _file_formatter
486
}
487
488
def on_model_change(self, form, model, is_created):
489
# Set uploaded_by to current user
490
if is_created:
491
model.uploaded_by = current_user._get_current_object()
492
```
493
494
### Custom Actions for MongoDB
495
496
```python
497
from flask_admin.actions import action
498
from flask import flash
499
500
class UserModelView(ModelView):
501
@action('activate', 'Activate Users', 'Activate selected users?')
502
def action_activate(self, ids):
503
try:
504
# Bulk update using MongoEngine
505
count = User.objects(id__in=ids).update(set__is_active=True)
506
flash(f'Successfully activated {count} users.', 'success')
507
except Exception as ex:
508
flash(f'Failed to activate users: {str(ex)}', 'error')
509
510
@action('send_email', 'Send Welcome Email')
511
def action_send_email(self, ids):
512
try:
513
users = User.objects(id__in=ids)
514
for user in users:
515
# Send email logic here
516
send_welcome_email(user.email)
517
flash(f'Sent emails to {len(users)} users.', 'success')
518
except Exception as ex:
519
flash(f'Failed to send emails: {str(ex)}', 'error')
520
```