Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
flask-admin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Python-Dev
flask-admin
Commits
f2107232
Commit
f2107232
authored
Aug 27, 2013
by
Serge S. Koval
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
AJAX ReferenceField in subdocuments support. Fixed #296
parent
0e4f34fa
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
111 additions
and
10 deletions
+111
-10
simple.py
examples/mongoengine/simple.py
+1
-0
ajax.py
flask_admin/contrib/mongoengine/ajax.py
+59
-4
view.py
flask_admin/contrib/mongoengine/view.py
+14
-2
form.py
flask_admin/contrib/sqla/form.py
+1
-1
filters.py
flask_admin/model/filters.py
+1
-1
test_basic.py
flask_admin/tests/mongoengine/test_basic.py
+33
-0
test_inlineform.py
flask_admin/tests/sqlamodel/test_inlineform.py
+2
-2
No files found.
examples/mongoengine/simple.py
View file @
f2107232
...
@@ -50,6 +50,7 @@ class Tag(db.Document):
...
@@ -50,6 +50,7 @@ class Tag(db.Document):
class
Comment
(
db
.
EmbeddedDocument
):
class
Comment
(
db
.
EmbeddedDocument
):
name
=
db
.
StringField
(
max_length
=
20
,
required
=
True
)
name
=
db
.
StringField
(
max_length
=
20
,
required
=
True
)
value
=
db
.
StringField
(
max_length
=
20
)
value
=
db
.
StringField
(
max_length
=
20
)
tag
=
db
.
ReferenceField
(
Tag
)
class
Post
(
db
.
Document
):
class
Post
(
db
.
Document
):
...
...
flask_admin/contrib/mongoengine/ajax.py
View file @
f2107232
import
mongoengine
import
mongoengine
from
flask.ext.admin._compat
import
string_types
,
as_unicode
from
flask.ext.admin._compat
import
string_types
,
as_unicode
,
iteritems
from
flask.ext.admin.model.ajax
import
AjaxModelLoader
,
DEFAULT_PAGE_SIZE
from
flask.ext.admin.model.ajax
import
AjaxModelLoader
,
DEFAULT_PAGE_SIZE
...
@@ -47,11 +47,11 @@ class QueryAjaxModelLoader(AjaxModelLoader):
...
@@ -47,11 +47,11 @@ class QueryAjaxModelLoader(AjaxModelLoader):
return
query
.
limit
(
limit
)
.
all
()
return
query
.
limit
(
limit
)
.
all
()
def
create_ajax_loader
(
model
,
name
,
fields
):
def
create_ajax_loader
(
model
,
name
,
field
_name
,
field
s
):
prop
=
getattr
(
model
,
name
,
None
)
prop
=
getattr
(
model
,
field_
name
,
None
)
if
prop
is
None
:
if
prop
is
None
:
raise
ValueError
(
'Model
%
s does not have field
%
s.'
%
(
model
,
name
))
raise
ValueError
(
'Model
%
s does not have field
%
s.'
%
(
model
,
field_
name
))
# TODO: Check for field
# TODO: Check for field
...
@@ -70,3 +70,58 @@ def create_ajax_loader(model, name, fields):
...
@@ -70,3 +70,58 @@ def create_ajax_loader(model, name, fields):
remote_fields
.
append
(
field
)
remote_fields
.
append
(
field
)
return
QueryAjaxModelLoader
(
name
,
remote_model
,
remote_fields
)
return
QueryAjaxModelLoader
(
name
,
remote_model
,
remote_fields
)
def
process_ajax_references
(
references
,
view
):
def
make_name
(
base
,
name
):
if
base
:
return
(
'
%
s-
%
s'
%
(
base
,
name
))
.
lower
()
else
:
return
as_unicode
(
name
)
.
lower
()
def
handle_field
(
field
,
subdoc
,
base
):
ftype
=
type
(
field
)
.
__name__
if
ftype
==
'ListField'
:
child_doc
=
getattr
(
subdoc
,
'_form_subdocuments'
,
{})
.
get
(
None
)
if
child_doc
:
handle_field
(
field
.
field
,
child_doc
,
base
)
elif
ftype
==
'EmbeddedDocumentField'
:
result
=
{}
ajax_refs
=
getattr
(
subdoc
,
'form_ajax_refs'
,
{})
for
field_name
,
opts
in
iteritems
(
ajax_refs
):
child_name
=
make_name
(
base
,
field_name
)
if
isinstance
(
opts
,
(
list
,
tuple
)):
loader
=
create_ajax_loader
(
field
.
document_type_obj
,
child_name
,
field_name
,
opts
)
else
:
loader
=
opts
result
[
field_name
]
=
loader
references
[
child_name
]
=
loader
subdoc
.
_form_ajax_refs
=
result
child_doc
=
getattr
(
subdoc
,
'_form_subdocuments'
,
None
)
if
child_doc
:
handle_subdoc
(
field
.
document_type_obj
,
subdoc
,
base
)
else
:
raise
ValueError
(
'Failed to process subdocument field
%
s'
%
(
field
,))
def
handle_subdoc
(
model
,
subdoc
,
base
):
documents
=
getattr
(
subdoc
,
'_form_subdocuments'
,
{})
for
name
,
doc
in
iteritems
(
documents
):
field
=
getattr
(
model
,
name
,
None
)
if
not
field
:
raise
ValueError
(
'Invalid subdocument field
%
s.
%
s'
)
handle_field
(
field
,
doc
,
make_name
(
base
,
name
))
handle_subdoc
(
view
.
model
,
view
,
''
)
return
references
flask_admin/contrib/mongoengine/view.py
View file @
f2107232
...
@@ -18,7 +18,7 @@ from .form import get_form, CustomModelConverter
...
@@ -18,7 +18,7 @@ from .form import get_form, CustomModelConverter
from
.typefmt
import
DEFAULT_FORMATTERS
from
.typefmt
import
DEFAULT_FORMATTERS
from
.tools
import
parse_like_term
from
.tools
import
parse_like_term
from
.helpers
import
format_error
from
.helpers
import
format_error
from
.ajax
import
QueryAjaxModelLoader
,
create_ajax_loader
from
.ajax
import
process_ajax_references
,
create_ajax_loader
from
.subdoc
import
convert_subdocuments
from
.subdoc
import
convert_subdocuments
...
@@ -213,6 +213,18 @@ class ModelView(BaseModelView):
...
@@ -213,6 +213,18 @@ class ModelView(BaseModelView):
# Cache other properties
# Cache other properties
super
(
ModelView
,
self
)
.
_refresh_cache
()
super
(
ModelView
,
self
)
.
_refresh_cache
()
def
_process_ajax_references
(
self
):
"""
AJAX endpoint is exposed by top-level admin view class, but
subdocuments might have AJAX references too.
This method will recursively go over subdocument configuration
and will precompute AJAX references for them ensuring that
subdocuments can also use AJAX to populate their ReferenceFields.
"""
references
=
super
(
ModelView
,
self
)
.
_process_ajax_references
()
return
process_ajax_references
(
references
,
self
)
def
_get_model_fields
(
self
,
model
=
None
):
def
_get_model_fields
(
self
,
model
=
None
):
"""
"""
Inspect model and return list of model fields
Inspect model and return list of model fields
...
@@ -353,7 +365,7 @@ class ModelView(BaseModelView):
...
@@ -353,7 +365,7 @@ class ModelView(BaseModelView):
# AJAX foreignkey support
# AJAX foreignkey support
def
_create_ajax_loader
(
self
,
name
,
fields
):
def
_create_ajax_loader
(
self
,
name
,
fields
):
return
create_ajax_loader
(
self
.
model
,
name
,
fields
)
return
create_ajax_loader
(
self
.
model
,
name
,
name
,
fields
)
def
get_query
(
self
):
def
get_query
(
self
):
"""
"""
...
...
flask_admin/contrib/sqla/form.py
View file @
f2107232
...
@@ -495,7 +495,7 @@ class InlineModelConverter(InlineModelConverterBase):
...
@@ -495,7 +495,7 @@ class InlineModelConverter(InlineModelConverterBase):
if
refs
:
if
refs
:
for
name
,
opts
in
iteritems
(
refs
):
for
name
,
opts
in
iteritems
(
refs
):
new_name
=
'
%
s
.
%
s'
%
(
info
.
model
.
__name__
.
lower
(),
name
)
new_name
=
'
%
s
-
%
s'
%
(
info
.
model
.
__name__
.
lower
(),
name
)
loader
=
None
loader
=
None
if
isinstance
(
opts
,
(
list
,
tuple
)):
if
isinstance
(
opts
,
(
list
,
tuple
)):
...
...
flask_admin/model/filters.py
View file @
f2107232
...
@@ -123,7 +123,7 @@ def convert(*args):
...
@@ -123,7 +123,7 @@ def convert(*args):
"""
"""
Decorator for field to filter conversion routine.
Decorator for field to filter conversion routine.
See :mod:`flask.ext.admin.contrib.sqla
model
.filters` for usage example.
See :mod:`flask.ext.admin.contrib.sqla.filters` for usage example.
"""
"""
def
_inner
(
func
):
def
_inner
(
func
):
func
.
_converter_for
=
args
func
.
_converter_for
=
args
...
...
flask_admin/tests/mongoengine/test_basic.py
View file @
f2107232
...
@@ -425,3 +425,36 @@ def test_ajax_fk():
...
@@ -425,3 +425,36 @@ def test_ajax_fk():
ok_
(
mdl
.
model1
is
not
None
)
ok_
(
mdl
.
model1
is
not
None
)
eq_
(
mdl
.
model1
.
id
,
model
.
id
)
eq_
(
mdl
.
model1
.
id
,
model
.
id
)
eq_
(
mdl
.
model1
.
test1
,
u'first'
)
eq_
(
mdl
.
model1
.
test1
,
u'first'
)
def
test_nested_ajax_refs
():
app
,
db
,
admin
=
setup
()
# Check recursive
class
Comment
(
db
.
Document
):
name
=
db
.
StringField
(
max_length
=
20
,
required
=
True
)
value
=
db
.
StringField
(
max_length
=
20
)
class
Nested
(
db
.
EmbeddedDocument
):
name
=
db
.
StringField
(
max_length
=
20
,
required
=
True
)
comment
=
db
.
ReferenceField
(
Comment
)
class
Model1
(
db
.
Document
):
test1
=
db
.
StringField
(
max_length
=
20
)
nested
=
db
.
EmbeddedDocumentField
(
Nested
)
view1
=
CustomModelView
(
Model1
,
form_subdocuments
=
{
'nested'
:
{
'form_ajax_refs'
:
{
'comment'
:
[
'name'
]
}
}
}
)
form
=
view1
.
create_form
()
eq_
(
type
(
form
.
nested
.
form
.
comment
)
.
__name__
,
'AjaxSelectField'
)
print
view1
.
_form_ajax_refs
ok_
(
'nested-comment'
in
view1
.
_form_ajax_refs
)
flask_admin/tests/sqlamodel/test_inlineform.py
View file @
f2107232
...
@@ -137,7 +137,7 @@ def test_inline_form_ajax_fk():
...
@@ -137,7 +137,7 @@ def test_inline_form_ajax_fk():
form
=
view
.
create_form
()
form
=
view
.
create_form
()
user_info_form
=
form
.
info
.
unbound_field
.
args
[
0
]
user_info_form
=
form
.
info
.
unbound_field
.
args
[
0
]
loader
=
user_info_form
.
tag
.
args
[
0
]
loader
=
user_info_form
.
tag
.
args
[
0
]
eq_
(
loader
.
name
,
'userinfo
.
tag'
)
eq_
(
loader
.
name
,
'userinfo
-
tag'
)
eq_
(
loader
.
model
,
Tag
)
eq_
(
loader
.
model
,
Tag
)
ok_
(
'userinfo
.
tag'
in
view
.
_form_ajax_refs
)
ok_
(
'userinfo
-
tag'
in
view
.
_form_ajax_refs
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment