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
80b8377d
Commit
80b8377d
authored
Mar 20, 2012
by
Serge S. Koval
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactoring, column renaming.
parent
4f019346
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
148 additions
and
48 deletions
+148
-48
TODO.txt
TODO.txt
+3
-6
simple.py
examples/sqla/simple.py
+2
-1
sqlamodel.py
flask_adminex/ext/sqlamodel.py
+12
-15
model.py
flask_adminex/model.py
+127
-26
list.html
flask_adminex/templates/admin/model/list.html
+4
-0
No files found.
TODO.txt
View file @
80b8377d
- Core
- Core
- Pregenerate URLs for menu
- Pregenerate URLs for menu
- Override base URL (/admin/)
- Override base URL (/admin/)
- Model
a
dmin
- Model
A
dmin
- Ability to override sortable fields
Ability to sort by fields that are not visible?
- SQLA Model Admin
- SQLA Model Admin
- Sort by foreign key
- Sort by foreign key
- Validation of the joins in the query
- Validation of the joins in the query
- Automatic joined load for foreign keys
- Automatic joined load for foreign keys
- Automatic PK detection
- Automatic PK detection
- Ability to override displayed form fields
- Ability to rename list columns
- Ability to change form without messing with form creation
- Filtering
- Filtering
- Many2Many editing
- Many2Many editing
-
Many2One
editor
-
One2Many
editor
- File admin
- File admin
- Documentation
- Documentation
- Examples
- Examples
...
...
examples/sqla/simple.py
View file @
80b8377d
...
@@ -49,7 +49,8 @@ def index():
...
@@ -49,7 +49,8 @@ def index():
class
PostAdmin
(
sqlamodel
.
ModelView
):
class
PostAdmin
(
sqlamodel
.
ModelView
):
list_columns
=
(
'title'
,
'user'
)
list_columns
=
(
'title'
,
'user'
)
sortable_columns
=
dict
(
title
=
'title'
,
user
=
User
.
username
)
sortable_columns
=
(
'title'
,
(
'user'
,
User
.
username
))
rename_columns
=
dict
(
title
=
'Tiiitle'
)
def
__init__
(
self
,
session
):
def
__init__
(
self
,
session
):
super
(
PostAdmin
,
self
)
.
__init__
(
Post
,
session
)
super
(
PostAdmin
,
self
)
.
__init__
(
Post
,
session
)
...
...
flask_adminex/ext/sqlamodel.py
View file @
80b8377d
...
@@ -71,7 +71,7 @@ class ModelView(BaseModelView):
...
@@ -71,7 +71,7 @@ class ModelView(BaseModelView):
if
column
.
foreign_keys
or
column
.
primary_key
:
if
column
.
foreign_keys
or
column
.
primary_key
:
continue
continue
columns
.
append
(
(
p
.
key
,
self
.
prettify_name
(
p
.
key
))
)
columns
.
append
(
p
.
key
)
return
columns
return
columns
...
@@ -81,11 +81,7 @@ class ModelView(BaseModelView):
...
@@ -81,11 +81,7 @@ class ModelView(BaseModelView):
mapper
=
self
.
model
.
_sa_class_manager
.
mapper
mapper
=
self
.
model
.
_sa_class_manager
.
mapper
for
p
in
mapper
.
iterate_properties
:
for
p
in
mapper
.
iterate_properties
:
if
isinstance
(
p
,
RelationshipProperty
):
if
isinstance
(
p
,
ColumnProperty
):
if
p
.
direction
is
MANYTOONE
:
# TODO: Detect PK
columns
[
p
.
key
]
=
'
%
s.id'
%
p
.
target
.
name
elif
isinstance
(
p
,
ColumnProperty
):
# TODO: Check for multiple columns
# TODO: Check for multiple columns
column
=
p
.
columns
[
0
]
column
=
p
.
columns
[
0
]
...
@@ -103,22 +99,20 @@ class ModelView(BaseModelView):
...
@@ -103,22 +99,20 @@ class ModelView(BaseModelView):
converter
=
AdminModelConverter
(
self
.
session
))
converter
=
AdminModelConverter
(
self
.
session
))
# Database-related API
# Database-related API
def
get_list
(
self
,
page
,
sort_column
,
sort_desc
):
def
get_list
(
self
,
page
,
sort_column
,
sort_desc
,
execute
=
True
):
query
=
self
.
session
.
query
(
self
.
model
)
query
=
self
.
session
.
query
(
self
.
model
)
count
=
query
.
count
()
count
=
query
.
count
()
# Sorting
# Sorting
column
=
self
.
_get_column_by_idx
(
sort_column
)
if
sort_column
is
not
None
:
if
column
is
not
None
:
if
sort_column
in
self
.
_sortable_columns
:
name
=
column
[
0
]
sort_field
=
self
.
_sortable_columns
[
sort_column
]
if
name
in
self
.
_sortable_columns
:
sort_field
=
self
.
_sortable_columns
[
name
]
# Try to handle it as a string
# Try to handle it as a string
if
isinstance
(
sort_field
,
basestring
):
if
isinstance
(
sort_field
,
basestring
):
# Create automatic join if string contains dot
# Create automatic join against a table if column name
# contains dot.
if
'.'
in
sort_field
:
if
'.'
in
sort_field
:
parts
=
sort_field
.
split
(
'.'
,
1
)
parts
=
sort_field
.
split
(
'.'
,
1
)
query
=
query
.
join
(
parts
[
0
])
query
=
query
.
join
(
parts
[
0
])
...
@@ -139,7 +133,10 @@ class ModelView(BaseModelView):
...
@@ -139,7 +133,10 @@ class ModelView(BaseModelView):
query
=
query
.
limit
(
self
.
page_size
)
query
=
query
.
limit
(
self
.
page_size
)
return
count
,
query
.
all
()
if
execute
:
query
=
query
.
all
()
return
count
,
query
def
get_one
(
self
,
id
):
def
get_one
(
self
,
id
):
return
self
.
session
.
query
(
self
.
model
)
.
get
(
id
)
return
self
.
session
.
query
(
self
.
model
)
.
get
(
id
)
...
...
flask_adminex/model.py
View file @
80b8377d
...
@@ -50,26 +50,39 @@ class BaseModelView(BaseView):
...
@@ -50,26 +50,39 @@ class BaseModelView(BaseView):
class MyModelView(BaseModelView):
class MyModelView(BaseModelView):
list_columns = ('name', 'last_name', 'email')
list_columns = ('name', 'last_name', 'email')
"""
rename_columns
=
None
"""
Dictionary where key is column name and value is string to display.
If you want to rename column, use tuple instead of the name,
For example::
where first value is field name and second is display name.
You can also mix these values::
class MyModelView(BaseModelView):
class MyModelView(BaseModelView):
list_columns = (('name', 'First Name'),
rename_columns = dict(name='Name', last_name='Last Name')
('last_name', 'Family Name'),
'email')
"""
"""
sortable_columns
=
None
sortable_columns
=
None
"""
"""
Dictionary of the sortable columns names and property references
.
Collection of the sortable columns for the list view
.
If set to `None`, will get them from the model.
If set to `None`, will get them from the model.
For example::
For example::
class MyModelView(BaseModelView):
class MyModelView(BaseModelView):
sortable_columns = dict(name='name', user='user.id')
sortable_columns = ('name', 'last_name')
If you want to explicitly specify field/column to be used while
sorting, you can use tuple::
class MyModelView(BaseModelView):
sortable_columns = ('name', ('user', 'user.username'))
For SQLAlchemy models, you can pass attribute instead of the string
too::
class MyModelView(BaseModelView):
sortable_columns = ('name', ('user', User.username))
"""
"""
form_columns
=
None
form_columns
=
None
...
@@ -136,9 +149,7 @@ class BaseModelView(BaseView):
...
@@ -136,9 +149,7 @@ class BaseModelView(BaseView):
Expected return format is list of tuples with field name and
Expected return format is list of tuples with field name and
display text. For example::
display text. For example::
[('name', 'Name'),
['name', 'first_name', 'last_name']
('email', 'Email'),
('last_name', 'Last Name')]
"""
"""
raise
NotImplemented
(
'Please implement scaffold_list_columns method'
)
raise
NotImplemented
(
'Please implement scaffold_list_columns method'
)
...
@@ -148,18 +159,20 @@ class BaseModelView(BaseView):
...
@@ -148,18 +159,20 @@ class BaseModelView(BaseView):
set, returns it. Otherwise calls `scaffold_list_columns`
set, returns it. Otherwise calls `scaffold_list_columns`
to generate list from the model.
to generate list from the model.
"""
"""
result
=
[]
if
self
.
list_columns
is
None
:
if
self
.
list_columns
is
None
:
columns
=
self
.
scaffold_list_columns
()
columns
=
self
.
scaffold_list_columns
()
else
:
else
:
columns
=
[]
columns
=
self
.
list_columns
for
c
in
self
.
list_
columns
:
for
c
in
columns
:
if
not
isinstance
(
c
,
tuple
)
:
if
self
.
rename_columns
and
c
in
self
.
rename_columns
:
columns
.
append
((
c
,
self
.
prettify_name
(
c
)
))
result
.
append
((
c
,
self
.
rename_columns
[
c
]
))
else
:
else
:
columns
.
append
(
c
)
result
.
append
((
c
,
self
.
prettify_name
(
c
))
)
return
columns
return
result
def
scaffold_sortable_columns
(
self
):
def
scaffold_sortable_columns
(
self
):
"""
"""
...
@@ -180,10 +193,17 @@ class BaseModelView(BaseView):
...
@@ -180,10 +193,17 @@ class BaseModelView(BaseView):
`scaffold_sortable_columns` to get them from the model.
`scaffold_sortable_columns` to get them from the model.
"""
"""
if
self
.
sortable_columns
is
None
:
if
self
.
sortable_columns
is
None
:
print
self
.
__class__
.
__name__
return
self
.
scaffold_sortable_columns
()
return
self
.
scaffold_sortable_columns
()
else
:
else
:
return
self
.
sortable_columns
result
=
dict
()
for
c
in
self
.
sortable_columns
:
if
isinstance
(
c
,
tuple
):
result
[
c
[
0
]]
=
c
[
1
]
else
:
result
[
c
]
=
c
return
result
def
scaffold_form
(
self
):
def
scaffold_form
(
self
):
"""
"""
...
@@ -226,9 +246,18 @@ class BaseModelView(BaseView):
...
@@ -226,9 +246,18 @@ class BaseModelView(BaseView):
# Helpers
# Helpers
def
is_sortable
(
self
,
name
):
def
is_sortable
(
self
,
name
):
"""
Verify if column is sortable.
`name`
Column name.
"""
return
name
in
self
.
_sortable_columns
return
name
in
self
.
_sortable_columns
def
_get_column_by_idx
(
self
,
idx
):
def
_get_column_by_idx
(
self
,
idx
):
"""
Return column index by
"""
if
idx
is
None
or
idx
<
0
or
idx
>=
len
(
self
.
_list_columns
):
if
idx
is
None
or
idx
<
0
or
idx
>=
len
(
self
.
_list_columns
):
return
None
return
None
...
@@ -245,31 +274,82 @@ class BaseModelView(BaseView):
...
@@ -245,31 +274,82 @@ class BaseModelView(BaseView):
`page`
`page`
Page number, 0 based. Can be set to None if it is first page.
Page number, 0 based. Can be set to None if it is first page.
`sort_field`
`sort_field`
Sort
field index in the `self.list_columns`
or None.
Sort
column name
or None.
`sort_desc`
`sort_desc`
If set to True, sorting is in descending order.
If set to True, sorting is in descending order.
"""
"""
raise
NotImplemented
(
'Please implement get_list method'
)
raise
NotImplemented
(
'Please implement get_list method'
)
def
get_one
(
self
,
id
):
def
get_one
(
self
,
id
):
"""
Return one model by its id.
Must be implemented in the child class.
`id`
Model id
"""
raise
NotImplemented
(
'Please implement get_one method'
)
raise
NotImplemented
(
'Please implement get_one method'
)
# Model handlers
# Model handlers
def
create_model
(
self
,
form
):
def
create_model
(
self
,
form
):
"""
Create model from the form.
Returns `True` if operation succeeded.
Must be implemented in the child class.
`form`
Form instance
"""
raise
NotImplemented
()
raise
NotImplemented
()
def
update_model
(
self
,
form
,
model
):
def
update_model
(
self
,
form
,
model
):
"""
Update model from the form.
Returns `True` if operation succeeded.
Must be implemented in the child class.
`form`
Form instance
`model`
Model instance
"""
raise
NotImplemented
()
raise
NotImplemented
()
def
delete_model
(
self
,
model
):
def
delete_model
(
self
,
model
):
"""
Delete model.
Returns `True` if operation succeeded.
Must be implemented in the child class.
`model`
Model instance
"""
raise
NotImplemented
()
raise
NotImplemented
()
# Various helpers
# Various helpers
def
prettify_name
(
self
,
name
):
def
prettify_name
(
self
,
name
):
"""
Prettify pythonic variable name.
For example, 'hello_world' will be converted to 'Hello World'
`name`
Name to prettify
"""
return
' '
.
join
(
x
.
capitalize
()
for
x
in
name
.
split
(
'_'
))
return
' '
.
join
(
x
.
capitalize
()
for
x
in
name
.
split
(
'_'
))
# URL generation helper
# URL generation helper
def
_get_extra_args
(
self
):
def
_get_extra_args
(
self
):
"""
Return arguments from query string.
"""
page
=
request
.
args
.
get
(
'page'
,
0
,
type
=
int
)
page
=
request
.
args
.
get
(
'page'
,
0
,
type
=
int
)
sort
=
request
.
args
.
get
(
'sort'
,
None
,
type
=
int
)
sort
=
request
.
args
.
get
(
'sort'
,
None
,
type
=
int
)
sort_desc
=
request
.
args
.
get
(
'desc'
,
None
,
type
=
int
)
sort_desc
=
request
.
args
.
get
(
'desc'
,
None
,
type
=
int
)
...
@@ -277,16 +357,37 @@ class BaseModelView(BaseView):
...
@@ -277,16 +357,37 @@ class BaseModelView(BaseView):
return
page
,
sort
,
sort_desc
return
page
,
sort
,
sort_desc
def
_get_url
(
self
,
view
,
page
,
sort
,
sort_desc
):
def
_get_url
(
self
,
view
,
page
,
sort
,
sort_desc
):
"""
Generate page URL with current page, sort column and
other parameters.
`view`
View name
`page`
Page number
`sort`
Sort column index
`sort_desc`
Use descending sorting order
"""
return
url_for
(
view
,
page
=
page
,
sort
=
sort
,
desc
=
sort_desc
)
return
url_for
(
view
,
page
=
page
,
sort
=
sort
,
desc
=
sort_desc
)
# Views
# Views
@
expose
(
'/'
)
@
expose
(
'/'
)
def
index_view
(
self
):
def
index_view
(
self
):
"""
List view
"""
# Grab parameters from URL
# Grab parameters from URL
page
,
sort
,
sort_desc
=
self
.
_get_extra_args
()
page
,
sort_idx
,
sort_desc
=
self
.
_get_extra_args
()
# Map column index to column name
sort_column
=
self
.
_get_column_by_idx
(
sort_idx
)
if
sort_column
is
not
None
:
sort_column
=
sort_column
[
0
]
# Get count and data
# Get count and data
count
,
data
=
self
.
get_list
(
page
,
sort
,
sort_desc
)
count
,
data
=
self
.
get_list
(
page
,
sort
_column
,
sort_desc
)
# Calculate number of pages
# Calculate number of pages
num_pages
=
count
/
self
.
page_size
num_pages
=
count
/
self
.
page_size
...
@@ -299,7 +400,7 @@ class BaseModelView(BaseView):
...
@@ -299,7 +400,7 @@ class BaseModelView(BaseView):
if
p
==
0
:
if
p
==
0
:
p
=
None
p
=
None
return
self
.
_get_url
(
'.index_view'
,
p
,
sort
,
sort_desc
)
return
self
.
_get_url
(
'.index_view'
,
p
,
sort
_idx
,
sort_desc
)
def
sort_url
(
column
,
invert
=
False
):
def
sort_url
(
column
,
invert
=
False
):
desc
=
None
desc
=
None
...
@@ -320,13 +421,13 @@ class BaseModelView(BaseView):
...
@@ -320,13 +421,13 @@ class BaseModelView(BaseView):
sortable_columns
=
self
.
_sortable_columns
,
sortable_columns
=
self
.
_sortable_columns
,
# Stuff
# Stuff
get_value
=
get_value
,
get_value
=
get_value
,
return_url
=
self
.
_get_url
(
'.index_view'
,
page
,
sort
,
sort_desc
),
return_url
=
self
.
_get_url
(
'.index_view'
,
page
,
sort
_idx
,
sort_desc
),
# Pagination
# Pagination
pager_url
=
pager_url
,
pager_url
=
pager_url
,
num_pages
=
num_pages
,
num_pages
=
num_pages
,
page
=
page
,
page
=
page
,
# Sorting
# Sorting
sort_column
=
sort
,
sort_column
=
sort
_idx
,
sort_desc
=
sort_desc
,
sort_desc
=
sort_desc
,
sort_url
=
sort_url
sort_url
=
sort_url
)
)
...
...
flask_adminex/templates/admin/model/list.html
View file @
80b8377d
...
@@ -9,6 +9,7 @@
...
@@ -9,6 +9,7 @@
{% set column = 0 %}
{% set column = 0 %}
{% for c, name in list_columns %}
{% for c, name in list_columns %}
<th>
<th>
{% if view.is_sortable(c) %}
{% if sort_column == column %}
{% if sort_column == column %}
<a
href=
"{{ sort_url(column, True) }}"
>
<a
href=
"{{ sort_url(column, True) }}"
>
{{ name }}
{{ name }}
...
@@ -21,6 +22,9 @@
...
@@ -21,6 +22,9 @@
{% else %}
{% else %}
<a
href=
"{{ sort_url(column) }}"
>
{{ name }}
</a>
<a
href=
"{{ sort_url(column) }}"
>
{{ name }}
</a>
{% endif %}
{% endif %}
{% else %}
{{ name }}
{% endif %}
</th>
</th>
{% set column = column + 1 %}
{% set column = column + 1 %}
{% endfor %}
{% endfor %}
...
...
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