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
cade92de
Commit
cade92de
authored
Aug 26, 2012
by
Serge S. Koval
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added inline sqlalchemy model admin (WIP)
parent
e81c1312
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
465 additions
and
135 deletions
+465
-135
simple.py
examples/sqla/simple.py
+18
-1
fields.py
flask_admin/contrib/sqlamodel/fields.py
+79
-1
form.py
flask_admin/contrib/sqlamodel/form.py
+115
-45
tools.py
flask_admin/contrib/sqlamodel/tools.py
+15
-0
view.py
flask_admin/contrib/sqlamodel/view.py
+20
-9
__init__.py
flask_admin/model/__init__.py
+1
-0
form.py
flask_admin/model/form.py
+12
-0
widgets.py
flask_admin/model/widgets.py
+22
-0
filters.js
flask_admin/static/js/filters.js
+2
-2
form.js
flask_admin/static/js/form.js
+71
-23
lib.html
flask_admin/templates/admin/lib.html
+53
-39
create.html
flask_admin/templates/admin/model/create.html
+13
-9
edit.html
flask_admin/templates/admin/model/edit.html
+4
-1
inline_form.html
flask_admin/templates/admin/model/inline_form.html
+2
-0
inline_form_list.html
flask_admin/templates/admin/model/inline_form_list.html
+32
-0
list.html
flask_admin/templates/admin/model/list.html
+6
-5
No files found.
examples/sqla/simple.py
View file @
cade92de
...
@@ -28,6 +28,18 @@ class User(db.Model):
...
@@ -28,6 +28,18 @@ class User(db.Model):
return
self
.
username
return
self
.
username
class
UserInfo
(
db
.
Model
):
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
)
key
=
db
.
Column
(
db
.
String
(
64
))
value
=
db
.
Column
(
db
.
String
(
64
))
user_id
=
db
.
Column
(
db
.
Integer
(),
db
.
ForeignKey
(
User
.
id
))
user
=
db
.
relationship
(
User
,
backref
=
'info'
)
def
__unicode__
(
self
):
return
'
%
s -
%
s'
%
(
self
.
key
,
self
.
value
)
# Create M2M table
# Create M2M table
post_tags_table
=
db
.
Table
(
'post_tags'
,
db
.
Model
.
metadata
,
post_tags_table
=
db
.
Table
(
'post_tags'
,
db
.
Model
.
metadata
,
db
.
Column
(
'post_id'
,
db
.
Integer
,
db
.
ForeignKey
(
'post.id'
)),
db
.
Column
(
'post_id'
,
db
.
Integer
,
db
.
ForeignKey
(
'post.id'
)),
...
@@ -64,6 +76,11 @@ def index():
...
@@ -64,6 +76,11 @@ def index():
return
'<a href="/admin/">Click me to get to Admin!</a>'
return
'<a href="/admin/">Click me to get to Admin!</a>'
# Customized User model admin
class
UserAdmin
(
sqlamodel
.
ModelView
):
inline_models
=
(
'info'
,)
# Customized Post model admin
# Customized Post model admin
class
PostAdmin
(
sqlamodel
.
ModelView
):
class
PostAdmin
(
sqlamodel
.
ModelView
):
# Visible columns in the list view
# Visible columns in the list view
...
@@ -100,7 +117,7 @@ if __name__ == '__main__':
...
@@ -100,7 +117,7 @@ if __name__ == '__main__':
admin
=
admin
.
Admin
(
app
,
'Simple Models'
)
admin
=
admin
.
Admin
(
app
,
'Simple Models'
)
# Add views
# Add views
admin
.
add_view
(
sqlamodel
.
ModelView
(
User
,
db
.
session
))
admin
.
add_view
(
UserAdmin
(
User
,
db
.
session
))
admin
.
add_view
(
sqlamodel
.
ModelView
(
Tag
,
db
.
session
))
admin
.
add_view
(
sqlamodel
.
ModelView
(
Tag
,
db
.
session
))
admin
.
add_view
(
PostAdmin
(
db
.
session
))
admin
.
add_view
(
PostAdmin
(
db
.
session
))
...
...
flask_admin/contrib/sqlamodel/fields.py
View file @
cade92de
...
@@ -4,9 +4,14 @@
...
@@ -4,9 +4,14 @@
import
operator
import
operator
from
wtforms
import
widgets
from
wtforms
import
widgets
from
wtforms.fields
import
SelectFieldBase
from
wtforms.fields
import
SelectFieldBase
,
FormField
,
FieldList
from
wtforms.validators
import
ValidationError
from
wtforms.validators
import
ValidationError
from
.tools
import
get_primary_key
from
flask.ext.admin.model.widgets
import
InlineFormListWidget
from
flask
import
request
try
:
try
:
from
sqlalchemy.orm.util
import
identity_key
from
sqlalchemy.orm.util
import
identity_key
has_identity_key
=
True
has_identity_key
=
True
...
@@ -176,6 +181,79 @@ class QuerySelectMultipleField(QuerySelectField):
...
@@ -176,6 +181,79 @@ class QuerySelectMultipleField(QuerySelectField):
raise
ValidationError
(
self
.
gettext
(
'Not a valid choice'
))
raise
ValidationError
(
self
.
gettext
(
'Not a valid choice'
))
class
InlineModelFormField
(
FormField
):
def
__init__
(
self
,
form
,
model
,
**
kwargs
):
super
(
InlineModelFormField
,
self
)
.
__init__
(
form
,
**
kwargs
)
self
.
model
=
model
self
.
_pk
=
get_primary_key
(
model
)
self
.
_should_delete
=
False
def
process
(
self
,
formdata
,
data
=
None
):
super
(
InlineModelFormField
,
self
)
.
process
(
formdata
,
data
)
# Grab delete key
key
=
'del-
%
s'
%
self
.
id
if
key
in
request
.
form
:
self
.
_should_delete
=
True
def
should_delete
(
self
):
return
self
.
_should_delete
def
get_pk
(
self
):
return
getattr
(
self
.
form
,
self
.
_pk
)
.
data
def
populate_obj
(
self
,
obj
,
name
):
for
name
,
field
in
self
.
form
.
_fields
.
iteritems
():
if
name
!=
self
.
_pk
:
field
.
populate_obj
(
obj
,
name
)
class
InlineModelFormList
(
FieldList
):
widget
=
InlineFormListWidget
()
def
__init__
(
self
,
form
,
session
,
model
,
**
kwargs
):
self
.
form
=
form
self
.
session
=
session
self
.
model
=
model
self
.
_pk
=
get_primary_key
(
model
)
super
(
InlineModelFormList
,
self
)
.
__init__
(
InlineModelFormField
(
form
,
model
),
**
kwargs
)
def
__call__
(
self
,
**
kwargs
):
return
self
.
widget
(
self
,
template
=
self
.
form
(),
**
kwargs
)
def
populate_obj
(
self
,
obj
,
name
):
values
=
getattr
(
obj
,
name
,
None
)
if
values
is
None
:
return
# Create primary key map
pk_map
=
dict
((
str
(
getattr
(
v
,
self
.
_pk
)),
v
)
for
v
in
values
)
# Create fake object to work around wtforms limitations
for
field
in
self
.
entries
:
field_id
=
field
.
get_pk
()
if
field_id
in
pk_map
:
model
=
pk_map
[
field_id
]
if
field
.
should_delete
():
self
.
session
.
delete
(
model
)
continue
else
:
model
=
self
.
model
()
values
.
append
(
model
)
field
.
populate_obj
(
model
,
None
)
# Force relation
model
.
user
=
obj
def
get_pk_from_identity
(
obj
):
def
get_pk_from_identity
(
obj
):
cls
,
key
=
identity_key
(
instance
=
obj
)
cls
,
key
=
identity_key
(
instance
=
obj
)
return
u':'
.
join
(
unicode
(
x
)
for
x
in
key
)
return
u':'
.
join
(
unicode
(
x
)
for
x
in
key
)
flask_admin/contrib/sqlamodel/form.py
View file @
cade92de
from
wtforms
import
fields
,
validators
from
wtforms
import
fields
,
validators
from
flask.ext.admin
import
form
from
flask.ext.admin
import
form
from
flask.ext.admin.model.form
import
converts
,
ModelConverterBase
from
flask.ext.admin.model.form
import
converts
,
ModelConverterBase
,
InlineFormAdmin
from
.validators
import
Unique
from
.validators
import
Unique
from
.fields
import
QuerySelectField
,
QuerySelectMultipleField
from
.fields
import
QuerySelectField
,
QuerySelectMultipleField
,
InlineModelFormList
class
AdminModelConverter
(
ModelConverterBase
):
class
AdminModelConverter
(
ModelConverterBase
):
"""
"""
SQLAlchemy model to form converter
SQLAlchemy model to form converter
"""
"""
def
__init__
(
self
,
view
):
def
__init__
(
self
,
session
,
view
):
super
(
AdminModelConverter
,
self
)
.
__init__
()
super
(
AdminModelConverter
,
self
)
.
__init__
()
self
.
session
=
session
self
.
view
=
view
self
.
view
=
view
def
_get_label
(
self
,
name
,
field_args
):
def
_get_label
(
self
,
name
,
field_args
):
if
'label'
in
field_args
:
if
'label'
in
field_args
:
return
field_args
[
'label'
]
return
field_args
[
'label'
]
if
self
.
view
.
rename_columns
:
rename_columns
=
getattr
(
self
.
view
,
'rename_columns'
,
None
)
return
self
.
view
.
rename_columns
.
get
(
name
)
if
rename_columns
:
return
rename_columns
.
get
(
name
)
return
None
return
None
def
_get_field_override
(
self
,
name
):
def
_get_field_override
(
self
,
name
):
if
self
.
view
.
form_overrides
:
form_overrides
=
getattr
(
self
.
view
,
'form_overrides'
,
None
)
return
self
.
view
.
form_overrides
.
get
(
name
)
if
form_overrides
:
return
form_overrides
.
get
(
name
)
return
None
return
None
def
convert
(
self
,
model
,
mapper
,
prop
,
field_args
):
def
convert
(
self
,
model
,
mapper
,
prop
,
field_args
,
hidden_pk
):
kwargs
=
{
kwargs
=
{
'validators'
:
[],
'validators'
:
[],
'filters'
:
[]
'filters'
:
[]
...
@@ -48,7 +53,7 @@ class AdminModelConverter(ModelConverterBase):
...
@@ -48,7 +53,7 @@ class AdminModelConverter(ModelConverterBase):
kwargs
.
update
({
kwargs
.
update
({
'allow_blank'
:
local_column
.
nullable
,
'allow_blank'
:
local_column
.
nullable
,
'label'
:
self
.
_get_label
(
prop
.
key
,
kwargs
),
'label'
:
self
.
_get_label
(
prop
.
key
,
kwargs
),
'query_factory'
:
lambda
:
self
.
view
.
session
.
query
(
remote_model
)
'query_factory'
:
lambda
:
self
.
session
.
query
(
remote_model
)
})
})
if
local_column
.
nullable
:
if
local_column
.
nullable
:
...
@@ -66,7 +71,7 @@ class AdminModelConverter(ModelConverterBase):
...
@@ -66,7 +71,7 @@ class AdminModelConverter(ModelConverterBase):
**
kwargs
)
**
kwargs
)
elif
prop
.
direction
.
name
==
'ONETOMANY'
:
elif
prop
.
direction
.
name
==
'ONETOMANY'
:
# Skip backrefs
# Skip backrefs
if
not
local_column
.
foreign_keys
and
self
.
view
.
hide_backrefs
:
if
not
local_column
.
foreign_keys
and
getattr
(
self
.
view
,
'hide_backrefs'
,
False
)
:
return
None
return
None
return
QuerySelectMultipleField
(
return
QuerySelectMultipleField
(
...
@@ -93,22 +98,28 @@ class AdminModelConverter(ModelConverterBase):
...
@@ -93,22 +98,28 @@ class AdminModelConverter(ModelConverterBase):
unique
=
False
unique
=
False
if
column
.
primary_key
:
if
column
.
primary_key
:
# By default, don't show primary keys either
if
hidden_pk
:
if
self
.
view
.
form_columns
is
None
:
# If requested to add hidden field, show it
return
None
return
fields
.
HiddenField
()
else
:
# By default, don't show primary keys either
form_columns
=
getattr
(
self
.
view
,
'form_columns'
,
None
)
# If PK is not explicitly allowed, ignore it
if
form_columns
is
None
:
if
prop
.
key
not
in
self
.
view
.
form_columns
:
return
None
return
None
kwargs
[
'validators'
]
.
append
(
Unique
(
self
.
view
.
session
,
# If PK is not explicitly allowed, ignore it
model
,
if
prop
.
key
not
in
form_columns
:
column
))
return
None
unique
=
True
kwargs
[
'validators'
]
.
append
(
Unique
(
self
.
session
,
model
,
column
))
unique
=
True
# If field is unique, validate it
# If field is unique, validate it
if
column
.
unique
and
not
unique
:
if
column
.
unique
and
not
unique
:
kwargs
[
'validators'
]
.
append
(
Unique
(
self
.
view
.
session
,
kwargs
[
'validators'
]
.
append
(
Unique
(
self
.
session
,
model
,
model
,
column
))
column
))
...
@@ -221,27 +232,86 @@ class AdminModelConverter(ModelConverterBase):
...
@@ -221,27 +232,86 @@ class AdminModelConverter(ModelConverterBase):
field_args
[
'validators'
]
.
append
(
validators
.
UUID
())
field_args
[
'validators'
]
.
append
(
validators
.
UUID
())
return
fields
.
TextField
(
**
field_args
)
return
fields
.
TextField
(
**
field_args
)
# Get list of fields and generate form
def
get_form
(
self
,
model
,
base_class
=
form
.
BaseForm
,
# Get list of fields and generate form
only
=
None
,
exclude
=
None
,
def
get_form
(
model
,
converter
,
field_args
=
None
):
base_class
=
form
.
BaseForm
,
# TODO: Support new 0.8 API
only
=
None
,
exclude
=
None
,
if
not
hasattr
(
model
,
'_sa_class_manager'
):
field_args
=
None
,
raise
TypeError
(
'model must be a sqlalchemy mapped model'
)
hidden_pk
=
False
):
mapper
=
model
.
_sa_class_manager
.
mapper
# TODO: Support new 0.8 API
field_args
=
field_args
or
{}
if
not
hasattr
(
model
,
'_sa_class_manager'
):
raise
TypeError
(
'model must be a sqlalchemy mapped model'
)
properties
=
((
p
.
key
,
p
)
for
p
in
mapper
.
iterate_properties
)
if
only
:
mapper
=
model
.
_sa_class_manager
.
mapper
properties
=
(
x
for
x
in
properties
if
x
[
0
]
in
only
)
field_args
=
field_args
or
{}
elif
exclude
:
properties
=
(
x
for
x
in
properties
if
x
[
0
]
not
in
exclude
)
properties
=
((
p
.
key
,
p
)
for
p
in
mapper
.
iterate_properties
)
if
only
:
field_dict
=
{}
properties
=
(
x
for
x
in
properties
if
x
[
0
]
in
only
)
for
name
,
prop
in
properties
:
elif
exclude
:
field
=
self
.
convert
(
model
,
mapper
,
prop
,
field_args
.
get
(
name
))
properties
=
(
x
for
x
in
properties
if
x
[
0
]
not
in
exclude
)
if
field
is
not
None
:
field_dict
[
name
]
=
field
field_dict
=
{}
for
name
,
prop
in
properties
:
return
type
(
model
.
__name__
+
'Form'
,
(
base_class
,
),
field_dict
)
field
=
converter
.
convert
(
model
,
mapper
,
prop
,
field_args
.
get
(
name
),
hidden_pk
)
if
field
is
not
None
:
field_dict
[
name
]
=
field
return
type
(
model
.
__name__
+
'Form'
,
(
base_class
,
),
field_dict
)
def
contribute_inline
(
session
,
model
,
form_class
,
inline_models
):
# Get mapper
mapper
=
model
.
_sa_class_manager
.
mapper
# Contribute columns
for
p
in
inline_models
:
# Figure out
if
isinstance
(
p
,
basestring
):
info
=
InlineFormAdmin
(
p
)
elif
isinstance
(
p
,
tuple
):
info
=
InlineFormAdmin
(
p
[
0
],
**
p
[
1
])
elif
isinstance
(
p
,
InlineFormAdmin
):
info
=
p
else
:
raise
Exception
(
'Unknown inline model admin:
%
s'
%
repr
(
p
))
prop
=
mapper
.
get_property
(
info
.
field
)
if
prop
is
None
:
raise
Exception
(
'Inline form property
%
s.
%
s was not found'
%
(
model
.
__name__
,
info
.
field
))
if
not
hasattr
(
prop
,
'direction'
):
raise
Exception
(
'Failed to convert inline admin
%
s - only one-to-many relations are supported'
%
info
.
field
)
if
prop
.
direction
.
name
!=
'ONETOMANY'
:
raise
Exception
(
'Failed to convert inline admin
%
s - only one-to-many relations are supported'
%
info
.
field
)
# Find reverse relationship (to exlude from the list)
ignore
=
[]
for
remote_prop
in
prop
.
mapper
.
iterate_properties
:
if
hasattr
(
remote_prop
,
'direction'
)
and
remote_prop
.
direction
.
name
==
'MANYTOONE'
:
if
remote_prop
.
mapper
.
class_
==
prop
.
parent
.
class_
:
ignore
.
append
(
remote_prop
.
key
)
print
remote_prop
.
key
if
info
.
exclude
:
exclude
=
ignore
+
info
.
exclude
else
:
exclude
=
ignore
# Create field
remote_model
=
prop
.
mapper
.
class_
converter
=
AdminModelConverter
(
session
,
info
)
child_form
=
get_form
(
remote_model
,
converter
,
only
=
info
.
include
,
exclude
=
exclude
,
hidden_pk
=
True
)
setattr
(
form_class
,
p
,
InlineModelFormList
(
child_form
,
session
,
remote_model
))
return
form_class
flask_admin/contrib/sqlamodel/tools.py
View file @
cade92de
...
@@ -7,3 +7,18 @@ def parse_like_term(term):
...
@@ -7,3 +7,18 @@ def parse_like_term(term):
stmt
=
'
%%%
s
%%
'
%
term
stmt
=
'
%%%
s
%%
'
%
term
return
stmt
return
stmt
def
get_primary_key
(
model
):
"""
Return primary key name from a model
"""
props
=
model
.
_sa_class_manager
.
mapper
.
iterate_properties
for
p
in
props
:
if
hasattr
(
p
,
'columns'
):
for
c
in
p
.
columns
:
if
c
.
primary_key
:
return
p
.
key
return
None
flask_admin/contrib/sqlamodel/view.py
View file @
cade92de
...
@@ -124,6 +124,17 @@ class ModelView(BaseModelView):
...
@@ -124,6 +124,17 @@ class ModelView(BaseModelView):
for your model.
for your model.
"""
"""
inline_models
=
None
"""
Inline related-model editing for parent to child relation.
If you have child relation with name 'posts', you can generate inline
administration interface by using this code::
class MyModelView(BaseModelView):
inline_models = ('posts',)
"""
def
__init__
(
self
,
model
,
session
,
def
__init__
(
self
,
model
,
session
,
name
=
None
,
category
=
None
,
endpoint
=
None
,
url
=
None
):
name
=
None
,
category
=
None
,
endpoint
=
None
,
url
=
None
):
"""
"""
...
@@ -178,13 +189,7 @@ class ModelView(BaseModelView):
...
@@ -178,13 +189,7 @@ class ModelView(BaseModelView):
"""
"""
Return primary key name from a model
Return primary key name from a model
"""
"""
for
p
in
self
.
_get_model_iterator
():
return
tools
.
get_primary_key
(
self
.
model
)
if
hasattr
(
p
,
'columns'
):
for
c
in
p
.
columns
:
if
c
.
primary_key
:
return
p
.
key
return
None
def
get_pk_value
(
self
,
model
):
def
get_pk_value
(
self
,
model
):
"""
"""
...
@@ -370,12 +375,18 @@ class ModelView(BaseModelView):
...
@@ -370,12 +375,18 @@ class ModelView(BaseModelView):
"""
"""
Create form from the model.
Create form from the model.
"""
"""
converter
=
form
.
AdminModelConverter
(
self
)
converter
=
form
.
AdminModelConverter
(
self
.
session
,
self
)
return
converter
.
get_form
(
self
.
model
,
form_class
=
form
.
get_form
(
self
.
model
,
converter
,
only
=
self
.
form_columns
,
only
=
self
.
form_columns
,
exclude
=
self
.
excluded_form_columns
,
exclude
=
self
.
excluded_form_columns
,
field_args
=
self
.
form_args
)
field_args
=
self
.
form_args
)
if
self
.
inline_models
:
form_class
=
form
.
contribute_inline
(
self
.
session
,
self
.
model
,
form_class
,
self
.
inline_models
)
return
form_class
def
scaffold_auto_joins
(
self
):
def
scaffold_auto_joins
(
self
):
"""
"""
Return list of joined tables by going through the
Return list of joined tables by going through the
...
...
flask_admin/model/__init__.py
View file @
cade92de
from
.base
import
BaseModelView
from
.base
import
BaseModelView
from
.form
import
InlineFormAdmin
from
flask.ext.admin.actions
import
action
from
flask.ext.admin.actions
import
action
flask_admin/model/form.py
View file @
cade92de
...
@@ -10,6 +10,18 @@ def converts(*args):
...
@@ -10,6 +10,18 @@ def converts(*args):
return
_inner
return
_inner
class
InlineFormAdmin
(
object
):
def
__init__
(
self
,
field
,
**
kwargs
):
self
.
field
=
field
defaults
=
dict
(
include
=
None
,
exclude
=
None
)
defaults
.
update
(
kwargs
)
for
k
,
v
in
defaults
.
iteritems
():
setattr
(
self
,
k
,
v
)
class
ModelConverterBase
(
object
):
class
ModelConverterBase
(
object
):
def
__init__
(
self
,
converters
=
None
,
use_mro
=
True
):
def
__init__
(
self
,
converters
=
None
,
use_mro
=
True
):
self
.
use_mro
=
use_mro
self
.
use_mro
=
use_mro
...
...
flask_admin/model/widgets.py
0 → 100644
View file @
cade92de
from
flask.globals
import
_request_ctx_stack
class
RenderTemplateWidget
(
object
):
def
__init__
(
self
,
template
):
self
.
template
=
template
def
__call__
(
self
,
field
,
**
kwargs
):
ctx
=
_request_ctx_stack
.
top
jinja_env
=
ctx
.
app
.
jinja_env
print
kwargs
kwargs
[
'field'
]
=
field
template
=
jinja_env
.
get_template
(
self
.
template
)
return
template
.
render
(
kwargs
)
class
InlineFormListWidget
(
RenderTemplateWidget
):
def
__init__
(
self
):
super
(
InlineFormListWidget
,
self
)
.
__init__
(
'admin/model/inline_form_list.html'
)
flask_admin/static/js/filters.js
View file @
cade92de
var
AdminFilters
=
function
(
element
,
filters_element
,
adminForm
,
operations
,
options
,
types
)
{
var
AdminFilters
=
function
(
element
,
filters_element
,
operations
,
options
,
types
)
{
var
$root
=
$
(
element
);
var
$root
=
$
(
element
);
var
$container
=
$
(
'.filters'
,
$root
);
var
$container
=
$
(
'.filters'
,
$root
);
var
lastCount
=
0
;
var
lastCount
=
0
;
...
@@ -68,7 +68,7 @@ var AdminFilters = function(element, filters_element, adminForm, operations, opt
...
@@ -68,7 +68,7 @@ var AdminFilters = function(element, filters_element, adminForm, operations, opt
if
(
optId
in
types
)
{
if
(
optId
in
types
)
{
$field
.
attr
(
'data-role'
,
types
[
optId
]);
$field
.
attr
(
'data-role'
,
types
[
optId
]);
admin
Form
.
applyStyle
(
$field
,
types
[
optId
]);
fa
Form
.
applyStyle
(
$field
,
types
[
optId
]);
}
}
lastCount
+=
1
;
lastCount
+=
1
;
...
...
flask_admin/static/js/form.js
View file @
cade92de
var
AdminForm
=
function
()
{
(
function
()
{
this
.
applyStyle
=
function
(
el
,
name
)
{
var
AdminForm
=
function
()
{
switch
(
name
)
{
this
.
applyStyle
=
function
(
el
,
name
)
{
case
'chosen'
:
switch
(
name
)
{
$
(
el
).
chosen
();
case
'chosen'
:
break
;
$
(
el
).
chosen
();
case
'chosenblank'
:
break
;
$
(
el
).
chosen
({
allow_single_deselect
:
true
});
case
'chosenblank'
:
break
;
$
(
el
).
chosen
({
allow_single_deselect
:
true
});
case
'datepicker'
:
break
;
$
(
el
).
datepicker
();
case
'datepicker'
:
break
;
$
(
el
).
datepicker
();
case
'datetimepicker'
:
break
;
$
(
el
).
datepicker
({
displayTime
:
true
});
case
'datetimepicker'
:
break
;
$
(
el
).
datepicker
({
displayTime
:
true
});
break
;
}
};
this
.
addInlineModel
=
function
(
id
,
el
,
template
)
{
var
$el
=
$
(
el
);
var
$template
=
$
(
template
);
// Figure out new form ID
var
lastForm
=
$el
.
children
(
'.fa-inline-form'
).
last
();
var
prefix
=
id
+
'-0'
;
if
(
lastForm
.
length
>
0
)
{
var
parts
=
$
(
lastForm
[
0
]).
attr
(
'id'
).
split
(
'-'
);
idx
=
parseInt
(
parts
[
parts
.
length
-
1
])
+
1
;
prefix
=
id
+
'-'
+
idx
;
}
// Set form ID
$template
.
attr
(
'id'
,
prefix
);
// Fix form IDs
$
(
'[name]'
,
$template
).
each
(
function
(
e
)
{
var
me
=
$
(
this
);
me
.
attr
(
'id'
,
prefix
+
'-'
+
me
.
attr
(
'id'
));
me
.
attr
(
'name'
,
prefix
+
'-'
+
me
.
attr
(
'name'
));
});
$template
.
appendTo
(
$el
);
// Apply styles
this
.
applyGlobalStyles
(
$template
);
};
this
.
applyGlobalStyles
=
function
(
parent
)
{
$
(
'[data-role=chosen]'
,
parent
).
chosen
();
$
(
'[data-role=chosenblank]'
,
parent
).
chosen
({
allow_single_deselect
:
true
});
$
(
'[data-role=datepicker]'
,
parent
).
datepicker
();
$
(
'[data-role=datetimepicker]'
,
parent
).
datepicker
({
displayTime
:
true
});
};
};
};
}
};
// Add live event handler
$
(
'.fa-remove-form'
).
live
(
'click'
,
function
(
e
)
{
// Apply automatic styles
e
.
preventDefault
();
$
(
'[data-role=chosen]'
).
chosen
();
$
(
'[data-role=chosenblank]'
).
chosen
({
allow_single_deselect
:
true
});
var
form
=
$
(
this
).
closest
(
'.fa-inline-form'
);
$
(
'[data-role=datepicker]'
).
datepicker
();
form
.
remove
();
$
(
'[data-role=datetimepicker]'
).
datepicker
({
displayTime
:
true
});
});
// Expose faForm globally
var
faForm
=
window
.
faForm
=
new
AdminForm
();
// Apply global styles
faForm
.
applyGlobalStyles
(
document
);
})();
flask_admin/templates/admin/lib.html
View file @
cade92de
...
@@ -73,48 +73,62 @@
...
@@ -73,48 +73,62 @@
{% endif %}
{% endif %}
{%- endmacro %}
{%- endmacro %}
{% macro render_form(form, cancel_url, extra=None) -%}
{% macro render_form_fields(form, focus_set=False) %}
<form
action=
""
method=
"POST"
class=
"form-horizontal"
{%
if
form
.
has_file_field
%}
enctype=
"multipart/form-data"
{%
endif
%}
>
{{ form.hidden_tag() }}
<fieldset>
{{ form.hidden_tag() }}
{% for f in form if f.name != 'csrf_token' and f.name != 'csrf' %}
{% for f in form if f.type != 'HiddenField' and f.type != 'CSRFTokenField' %}
<div
class=
"control-group{% if f.errors %} error{% endif %}"
>
<div
class=
"control-group{% if f.errors %} error{% endif %}"
>
{{ f.label(class='control-label') }}
{{ f.label(class='control-label') }}
<div
class=
"controls"
>
<div
class=
"controls"
>
<div>
<div>
{% if not focus_set %}
{% if not focus_set %}
{{ f(autofocus='autofocus') }}
{{ f(autofocus='autofocus')|safe }}
{% set focus_set = True %}
{% set focus_set = True %}
{% else %}
{% else %}
{{ f() }}
{{ f()|safe }}
{% endif %}
{% endif %}
</div>
{% if f.description %}
<p
class=
"help-block"
>
{{ f.description }}
</p>
{% endif %}
{% if f.errors %}
<ul>
{% for e in f.errors %}
<li>
{{ e }}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endfor %}
<div
class=
"control-group"
>
<div
class=
"controls"
>
<input
type=
"submit"
class=
"btn btn-primary btn-large"
value=
"{{ _gettext('Submit') }}"
/>
{% if extra %}
{{ extra }}
{% endif %}
{% if cancel_url %}
<a
href=
"{{ cancel_url }}"
class=
"btn btn-large"
>
{{ _gettext('Cancel') }}
</a>
{% endif %}
</div>
</div>
</div>
{% if f.description %}
<p
class=
"help-block"
>
{{ f.description }}
</p>
{% endif %}
{% if f.errors %}
<ul>
{% for e in f.errors %}
<li>
{{ e }}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endfor %}
{% endmacro %}
{% macro form_tag() %}
<form
action=
""
method=
"POST"
class=
"form-horizontal"
{%
if
form
.
has_file_field
%}
enctype=
"multipart/form-data"
{%
endif
%}
>
<fieldset>
{{ caller() }}
</fieldset>
</fieldset>
</form>
</form>
{% endmacro %}
{% endmacro %}
{% macro render_form_buttons(cancel_url, extra=None) %}
<div
class=
"control-group"
>
<div
class=
"controls"
>
<input
type=
"submit"
class=
"btn btn-primary btn-large"
value=
"{{ _gettext('Submit') }}"
/>
{% if extra %}
{{ extra }}
{% endif %}
{% if cancel_url %}
<a
href=
"{{ cancel_url }}"
class=
"btn btn-large"
>
{{ _gettext('Cancel') }}
</a>
{% endif %}
</div>
</div>
{% endmacro %}
{% macro render_form(form, cancel_url, extra=None) -%}
{% call form_tag() %}
{{ render_form_fields(form) }}
{{ render_form_buttons(cancel_url, extra) }}
{% endcall %}
{% endmacro %}
flask_admin/templates/admin/model/create.html
View file @
cade92de
...
@@ -7,19 +7,23 @@
...
@@ -7,19 +7,23 @@
{% endblock %}
{% endblock %}
{% block body %}
{% block body %}
<ul
class=
"nav nav-tabs"
>
<li>
<a
href=
"{{ return_url }}"
>
{{ _gettext('List') }}
</a>
</li>
<li
class=
"active"
>
<a
href=
"#"
>
{{ _gettext('Create') }}
</a>
</li>
</ul>
{% macro extra() %}
{% macro extra() %}
<input
name=
"_add_another"
type=
"submit"
class=
"btn btn-large"
value=
"{{ _gettext('Save and Add') }}"
/>
<input
name=
"_add_another"
type=
"submit"
class=
"btn btn-large"
value=
"{{ _gettext('Save and Add') }}"
/>
{% endmacro %}
{% endmacro %}
<ul
class=
"nav nav-tabs"
>
{% call lib.form_tag() %}
<li>
{{ lib.render_form_fields(form) }}
<a
href=
"{{ return_url }}"
>
{{ _gettext('List') }}
</a>
{{ lib.render_form_buttons(cancel_url, extra()) }}
</li>
{% endcall %}
<li
class=
"active"
>
<a
href=
"#"
>
{{ _gettext('Create') }}
</a>
</li>
</ul>
{{ lib.render_form(form, return_url, extra()) }}
{% endblock %}
{% endblock %}
{% block tail %}
{% block tail %}
...
...
flask_admin/templates/admin/model/edit.html
View file @
cade92de
...
@@ -7,7 +7,10 @@
...
@@ -7,7 +7,10 @@
{% endblock %}
{% endblock %}
{% block body %}
{% block body %}
{{ lib.render_form(form, return_url) }}
{% call lib.form_tag() %}
{{ lib.render_form_fields(form) }}
{{ lib.render_form_buttons(cancel_url) }}
{% endcall %}
{% endblock %}
{% endblock %}
{% block tail %}
{% block tail %}
...
...
flask_admin/templates/admin/model/inline_form.html
0 → 100644
View file @
cade92de
{% import 'admin/lib.html' as lib with context %}
flask_admin/templates/admin/model/inline_form_list.html
0 → 100644
View file @
cade92de
{% import 'admin/lib.html' as lib with context %}
{% macro render_form(form) %}
{% endmacro %}
{% macro render_template(template) -%}
<div
class=
"fa-inline-form"
>
<div
style=
"float: right"
>
<a
href=
"#"
class=
"fa-remove-form"
>
x
</a>
</div>
{{ lib.render_form_fields(template) }}
<hr/>
</div>
{%- endmacro %}
<div
class=
"well"
>
<div
id=
"{{ field.id }}-forms"
>
{% for subfield in field %}
<div
id=
"{{ subfield.id }}"
class=
"fa-inline-form"
>
{% set pk = subfield.get_pk() %}
{%- if pk %}
<div
style=
"float: right"
>
<input
type=
"checkbox"
name=
"del-{{ subfield.id }}"
id=
"del-{{ subfield.id }}"
/>
Delete?
</div>
{%- endif -%}
{{ lib.render_form_fields(subfield, True) }}
<hr/>
</div>
{% endfor %}
</div>
<a
href=
"#"
class=
"btn"
onclick=
"faForm.addInlineModel('{{ field.id }}', '#{{ field.id }}-forms', {{ render_template(template)|tojson }});"
>
Add {{ field.name }}
</a>
</div>
flask_admin/templates/admin/model/list.html
View file @
cade92de
...
@@ -174,11 +174,12 @@
...
@@ -174,11 +174,12 @@
{% if filter_groups is not none and filter_data is not none %}
{% if filter_groups is not none and filter_data is not none %}
<script
language=
"javascript"
>
<script
language=
"javascript"
>
var
form
=
new
AdminForm
();
(
function
()
{
var
filter
=
new
AdminFilters
(
'#filter_form'
,
'.field-filters'
,
form
,
var
filter
=
new
AdminFilters
(
'#filter_form'
,
'.field-filters'
,
{{
admin_view
.
_filter_dict
|
tojson
|
safe
}},
{{
admin_view
.
_filter_dict
|
tojson
|
safe
}},
{{
filter_data
|
tojson
|
safe
}},
{{
filter_data
|
tojson
|
safe
}},
{{
filter_types
|
tojson
|
safe
}});
{{
filter_types
|
tojson
|
safe
}});
})();
</script>
</script>
{% endif %}
{% endif %}
{% endblock %}
{% endblock %}
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