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
ce5b36ef
Commit
ce5b36ef
authored
Aug 27, 2013
by
Serge S. Koval
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New data model for form_ajax_refs
parent
f2107232
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
83 additions
and
45 deletions
+83
-45
simple.py
examples/sqla/simple.py
+6
-2
ajax.py
flask_admin/contrib/sqla/ajax.py
+34
-26
form.py
flask_admin/contrib/sqla/form.py
+1
-1
view.py
flask_admin/contrib/sqla/view.py
+2
-2
ajax.py
flask_admin/model/ajax.py
+2
-1
base.py
flask_admin/model/base.py
+23
-10
test_basic.py
flask_admin/tests/sqlamodel/test_basic.py
+6
-2
test_inlineform.py
flask_admin/tests/sqlamodel/test_inlineform.py
+9
-1
No files found.
examples/sqla/simple.py
View file @
ce5b36ef
...
@@ -122,8 +122,12 @@ class PostAdmin(sqla.ModelView):
...
@@ -122,8 +122,12 @@ class PostAdmin(sqla.ModelView):
)
)
form_ajax_refs
=
{
form_ajax_refs
=
{
'user'
:
(
User
.
username
,
User
.
email
),
'user'
:
{
'tags'
:
(
Tag
.
name
,)
'fields'
:
(
User
.
username
,
User
.
email
)
},
'tags'
:
{
'fields'
:
(
Tag
.
name
,)
}
}
}
def
__init__
(
self
,
session
):
def
__init__
(
self
,
session
):
...
...
flask_admin/contrib/sqla/ajax.py
View file @
ce5b36ef
...
@@ -5,18 +5,23 @@ from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
...
@@ -5,18 +5,23 @@ from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
class
QueryAjaxModelLoader
(
AjaxModelLoader
):
class
QueryAjaxModelLoader
(
AjaxModelLoader
):
def
__init__
(
self
,
name
,
session
,
model
,
field
s
):
def
__init__
(
self
,
name
,
session
,
model
,
option
s
):
"""
"""
Constructor.
Constructor.
:param fields:
:param fields:
Fields to run query against
Fields to run query against
"""
"""
super
(
QueryAjaxModelLoader
,
self
)
.
__init__
(
name
)
super
(
QueryAjaxModelLoader
,
self
)
.
__init__
(
name
,
options
)
self
.
session
=
session
self
.
session
=
session
self
.
model
=
model
self
.
model
=
model
self
.
fields
=
fields
self
.
fields
=
options
.
get
(
'fields'
)
if
not
self
.
fields
:
raise
ValueError
(
'AJAX loading requires `fields` to be specified for
%
s.
%
s'
%
(
model
,
self
.
name
))
self
.
_cached_fields
=
self
.
_process_fields
()
primary_keys
=
model
.
_sa_class_manager
.
mapper
.
primary_key
primary_keys
=
model
.
_sa_class_manager
.
mapper
.
primary_key
if
len
(
primary_keys
)
>
1
:
if
len
(
primary_keys
)
>
1
:
...
@@ -24,6 +29,23 @@ class QueryAjaxModelLoader(AjaxModelLoader):
...
@@ -24,6 +29,23 @@ class QueryAjaxModelLoader(AjaxModelLoader):
self
.
pk
=
primary_keys
[
0
]
.
name
self
.
pk
=
primary_keys
[
0
]
.
name
def
_process_fields
(
self
):
remote_fields
=
[]
for
field
in
self
.
fields
:
if
isinstance
(
field
,
string_types
):
attr
=
getattr
(
self
.
model
,
field
,
None
)
if
not
attr
:
raise
ValueError
(
'
%
s.
%
s does not exist.'
%
(
self
.
model
,
field
))
remote_fields
.
append
(
attr
)
else
:
# TODO: Figure out if it is valid SQLAlchemy property?
remote_fields
.
append
(
field
)
return
remote_fields
def
format
(
self
,
model
):
def
format
(
self
,
model
):
if
not
model
:
if
not
model
:
return
None
return
None
...
@@ -36,34 +58,20 @@ class QueryAjaxModelLoader(AjaxModelLoader):
...
@@ -36,34 +58,20 @@ class QueryAjaxModelLoader(AjaxModelLoader):
def
get_list
(
self
,
term
,
offset
=
0
,
limit
=
DEFAULT_PAGE_SIZE
):
def
get_list
(
self
,
term
,
offset
=
0
,
limit
=
DEFAULT_PAGE_SIZE
):
query
=
self
.
session
.
query
(
self
.
model
)
query
=
self
.
session
.
query
(
self
.
model
)
filters
=
(
field
.
like
(
u'
%%%
s
%%
'
%
term
)
for
field
in
self
.
fields
)
filters
=
(
field
.
like
(
u'
%%%
s
%%
'
%
term
)
for
field
in
self
.
_cached_
fields
)
query
=
query
.
filter
(
or_
(
*
filters
))
query
=
query
.
filter
(
or_
(
*
filters
))
return
query
.
offset
(
offset
)
.
limit
(
limit
)
.
all
()
return
query
.
offset
(
offset
)
.
limit
(
limit
)
.
all
()
def
create_ajax_loader
(
model
,
session
,
name
,
field_name
,
fields
):
def
create_ajax_loader
(
model
,
session
,
name
,
field_name
,
options
):
attr
=
getattr
(
model
,
field_name
,
None
)
attr
=
getattr
(
model
,
field_name
,
None
)
if
attr
is
None
:
raise
ValueError
(
'Model
%
s does not have field
%
s.'
%
(
model
,
field_name
))
if
not
hasattr
(
attr
,
'property'
)
or
not
hasattr
(
attr
.
property
,
'direction'
):
raise
ValueError
(
'
%
s.
%
s is not a relation.'
%
(
model
,
field_name
))
remote_model
=
attr
.
prop
.
mapper
.
class_
remote_fields
=
[]
for
field
in
fields
:
if
isinstance
(
field
,
string_types
):
attr
=
getattr
(
remote_model
,
field
,
None
)
if
not
attr
:
if
attr
is
None
:
raise
ValueError
(
'
%
s.
%
s does not exist.'
%
(
remote_model
,
field
))
raise
ValueError
(
'Model
%
s does not have field
%
s.'
%
(
model
,
field_name
))
remote_fields
.
append
(
attr
)
if
not
hasattr
(
attr
,
'property'
)
or
not
hasattr
(
attr
.
property
,
'direction'
):
else
:
raise
ValueError
(
'
%
s.
%
s is not a relation.'
%
(
model
,
field_name
))
# TODO: Figure out if it is valid SQLAlchemy property?
remote_fields
.
append
(
field
)
return
QueryAjaxModelLoader
(
name
,
session
,
remote_model
,
remote_fields
)
remote_model
=
attr
.
prop
.
mapper
.
class_
return
QueryAjaxModelLoader
(
name
,
session
,
remote_model
,
options
)
flask_admin/contrib/sqla/form.py
View file @
ce5b36ef
...
@@ -498,7 +498,7 @@ class InlineModelConverter(InlineModelConverterBase):
...
@@ -498,7 +498,7 @@ class InlineModelConverter(InlineModelConverterBase):
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
,
dict
):
loader
=
create_ajax_loader
(
info
.
model
,
self
.
session
,
new_name
,
name
,
opts
)
loader
=
create_ajax_loader
(
info
.
model
,
self
.
session
,
new_name
,
name
,
opts
)
else
:
else
:
loader
=
opts
loader
=
opts
...
...
flask_admin/contrib/sqla/view.py
View file @
ce5b36ef
...
@@ -586,8 +586,8 @@ class ModelView(BaseModelView):
...
@@ -586,8 +586,8 @@ class ModelView(BaseModelView):
return
joined
return
joined
# AJAX foreignkey support
# AJAX foreignkey support
def
_create_ajax_loader
(
self
,
name
,
field
s
):
def
_create_ajax_loader
(
self
,
name
,
option
s
):
return
create_ajax_loader
(
self
.
model
,
self
.
session
,
name
,
name
,
field
s
)
return
create_ajax_loader
(
self
.
model
,
self
.
session
,
name
,
name
,
option
s
)
# Database-related API
# Database-related API
def
get_query
(
self
):
def
get_query
(
self
):
...
...
flask_admin/model/ajax.py
View file @
ce5b36ef
...
@@ -5,7 +5,7 @@ class AjaxModelLoader(object):
...
@@ -5,7 +5,7 @@ class AjaxModelLoader(object):
"""
"""
Ajax related model loader. Override this to implement custom loading behavior.
Ajax related model loader. Override this to implement custom loading behavior.
"""
"""
def
__init__
(
self
,
name
):
def
__init__
(
self
,
name
,
options
):
"""
"""
Constructor.
Constructor.
...
@@ -13,6 +13,7 @@ class AjaxModelLoader(object):
...
@@ -13,6 +13,7 @@ class AjaxModelLoader(object):
Field name
Field name
"""
"""
self
.
name
=
name
self
.
name
=
name
self
.
options
=
options
def
format
(
self
,
model
):
def
format
(
self
,
model
):
"""
"""
...
...
flask_admin/model/base.py
View file @
ce5b36ef
...
@@ -367,15 +367,28 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -367,15 +367,28 @@ class BaseModelView(BaseView, ActionsMixin):
"""
"""
Use AJAX for foreign key model loading.
Use AJAX for foreign key model loading.
Should contain dictionary, where key is field name and value is e
numerable with list to fields
Should contain dictionary, where key is field name and value is e
ither a dictionary which
to check against (in remote model)
.
configures AJAX lookups or backend-specific `AjaxModelLoader` class instance
.
For example, it can look like::
For example, it can look like::
class MyModelView(BaseModelView):
class MyModelView(BaseModelView):
form_ajax_refs = {
form_ajax_refs = {
'user': ('first_name', 'last_name', 'email')
'user': {
'fields': ('first_name', 'last_name', 'email')
'page_size': 10
}
}
}
Or with SQLAlchemy backend like this::
class MyModelView(BaseModelView):
form_ajax_refs = {
'user': QueryAjaxModelLoader('user', db.session, User, page_size=10)
}
If you need custom loading functionality, you can implement your custom loading behavior
in your `AjaxModelLoader` class.
"""
"""
# Actions
# Actions
...
@@ -998,17 +1011,17 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -998,17 +1011,17 @@ class BaseModelView(BaseView, ActionsMixin):
result
=
{}
result
=
{}
if
self
.
form_ajax_refs
:
if
self
.
form_ajax_refs
:
for
name
,
value
in
iteritems
(
self
.
form_ajax_refs
):
for
name
,
options
in
iteritems
(
self
.
form_ajax_refs
):
if
isinstance
(
value
,
AjaxModelLoader
):
if
isinstance
(
options
,
dict
):
result
[
name
]
=
value
result
[
name
]
=
self
.
_create_ajax_loader
(
name
,
options
)
elif
isinstance
(
value
,
(
list
,
tuple
)
):
elif
isinstance
(
options
,
AjaxModelLoader
):
result
[
name
]
=
self
.
_create_ajax_loader
(
name
,
value
)
result
[
name
]
=
options
else
:
else
:
raise
ValueError
(
'
%
s.form_ajax_refs can not handle
%
s types'
%
(
self
,
type
(
value
)))
raise
ValueError
(
'
%
s.form_ajax_refs can not handle
%
s types'
%
(
self
,
type
(
options
)))
return
result
return
result
def
_create_ajax_loader
(
self
,
name
,
field
s
):
def
_create_ajax_loader
(
self
,
name
,
option
s
):
"""
"""
Model backend will override this to implement AJAX model loading.
Model backend will override this to implement AJAX model loading.
"""
"""
...
...
flask_admin/tests/sqlamodel/test_basic.py
View file @
ce5b36ef
...
@@ -690,7 +690,9 @@ def test_ajax_fk():
...
@@ -690,7 +690,9 @@ def test_ajax_fk():
Model2
,
db
.
session
,
Model2
,
db
.
session
,
url
=
'view'
,
url
=
'view'
,
form_ajax_refs
=
{
form_ajax_refs
=
{
'model1'
:
(
'test1'
,
'test2'
)
'model1'
:
{
'fields'
:
(
'test1'
,
'test2'
)
}
}
}
)
)
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
...
@@ -774,7 +776,9 @@ def test_ajax_fk_multi():
...
@@ -774,7 +776,9 @@ def test_ajax_fk_multi():
Model2
,
db
.
session
,
Model2
,
db
.
session
,
url
=
'view'
,
url
=
'view'
,
form_ajax_refs
=
{
form_ajax_refs
=
{
'model1'
:
(
'name'
,)
'model1'
:
{
'fields'
:
[
'name'
]
}
}
}
)
)
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
...
...
flask_admin/tests/sqlamodel/test_inlineform.py
View file @
ce5b36ef
...
@@ -129,7 +129,15 @@ def test_inline_form_ajax_fk():
...
@@ -129,7 +129,15 @@ def test_inline_form_ajax_fk():
# Set up Admin
# Set up Admin
class
UserModelView
(
ModelView
):
class
UserModelView
(
ModelView
):
inline_models
=
[(
UserInfo
,
{
'form_ajax_refs'
:
{
'tag'
:
(
'name'
,)}})]
opts
=
{
'form_ajax_refs'
:
{
'tag'
:
{
'fields'
:
[
'name'
]
}
}
}
inline_models
=
[(
UserInfo
,
opts
)]
view
=
UserModelView
(
User
,
db
.
session
)
view
=
UserModelView
(
User
,
db
.
session
)
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
...
...
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