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
d7df4fe4
Commit
d7df4fe4
authored
Dec 30, 2015
by
Serge S. Koval
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1158 from pawl/add_hstore
Add support for HSTORE columns to SQLA backend
parents
35963bcc
675c2846
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
114 additions
and
8 deletions
+114
-8
.travis.yml
.travis.yml
+2
-1
fields.py
flask_admin/contrib/sqla/fields.py
+49
-5
form.py
flask_admin/contrib/sqla/form.py
+8
-1
fields.py
flask_admin/model/fields.py
+1
-1
__init__.py
flask_admin/tests/sqla/__init__.py
+12
-0
test_postgres.py
flask_admin/tests/sqla/test_postgres.py
+42
-0
No files found.
.travis.yml
View file @
d7df4fe4
...
@@ -16,7 +16,8 @@ services:
...
@@ -16,7 +16,8 @@ services:
before_script
:
before_script
:
-
psql -U postgres -c 'CREATE DATABASE flask_admin_test;'
-
psql -U postgres -c 'CREATE DATABASE flask_admin_test;'
-
psql -U postgres -c "CREATE EXTENSION postgis;" flask_admin_test
-
psql -U postgres -c 'CREATE EXTENSION postgis;' flask_admin_test
-
psql -U postgres -c 'CREATE EXTENSION hstore;' flask_admin_test
install
:
install
:
-
pip install "wtforms<$WTFORMS_VERSION.99"
-
pip install "wtforms<$WTFORMS_VERSION.99"
...
...
flask_admin/contrib/sqla/fields.py
View file @
d7df4fe4
...
@@ -4,15 +4,19 @@
...
@@ -4,15 +4,19 @@
import
operator
import
operator
from
wtforms
import
widgets
from
wtforms
import
widgets
from
wtforms.fields
import
SelectFieldBase
from
wtforms.fields
import
SelectFieldBase
,
TextField
from
wtforms.validators
import
ValidationError
from
wtforms.validators
import
ValidationError
try
:
from
wtforms.fields
import
_unset_value
as
unset_value
except
ImportError
:
from
wtforms.utils
import
unset_value
from
.tools
import
get_primary_key
from
.tools
import
get_primary_key
from
flask_admin._compat
import
text_type
,
string_types
from
flask_admin._compat
import
text_type
,
string_types
,
iteritems
from
flask_admin.form
import
FormOpts
from
flask_admin.form
import
FormOpts
,
BaseForm
from
flask_admin.model.fields
import
InlineFieldList
,
InlineModelFormField
from
flask_admin.model.fields
import
InlineFieldList
,
InlineModelFormField
from
flask_admin.model.widgets
import
InlineFormWidget
from
flask_admin.babel
import
lazy_gettext
try
:
try
:
from
sqlalchemy.orm.util
import
identity_key
from
sqlalchemy.orm.util
import
identity_key
...
@@ -178,6 +182,46 @@ class QuerySelectMultipleField(QuerySelectField):
...
@@ -178,6 +182,46 @@ class QuerySelectMultipleField(QuerySelectField):
raise
ValidationError
(
self
.
gettext
(
u'Not a valid choice'
))
raise
ValidationError
(
self
.
gettext
(
u'Not a valid choice'
))
class
HstoreForm
(
BaseForm
):
""" Form used in InlineFormField/InlineHstoreList for HSTORE columns """
key
=
TextField
(
lazy_gettext
(
'Key'
))
value
=
TextField
(
lazy_gettext
(
'Value'
))
class
KeyValue
(
object
):
""" Used by InlineHstoreList to simulate a key and a value field instead of
the single HSTORE column. """
def
__init__
(
self
,
key
=
None
,
value
=
None
):
self
.
key
=
key
self
.
value
=
value
class
InlineHstoreList
(
InlineFieldList
):
""" Version of InlineFieldList for use with Postgres HSTORE columns """
def
process
(
self
,
formdata
,
data
=
unset_value
):
""" SQLAlchemy returns a dict for HSTORE columns, but WTForms cannot
process a dict. This overrides `process` to convert the dict
returned by SQLAlchemy to a list of classes before processing. """
if
isinstance
(
data
,
dict
):
data
=
[
KeyValue
(
k
,
v
)
for
k
,
v
in
iteritems
(
data
)]
super
(
InlineHstoreList
,
self
)
.
process
(
formdata
,
data
)
def
populate_obj
(
self
,
obj
,
name
):
""" Combines each FormField key/value into a dictionary for storage """
_fake
=
type
(
str
(
'_fake'
),
(
object
,
),
{})
output
=
{}
for
form_field
in
self
.
entries
:
if
not
self
.
should_delete
(
form_field
):
fake_obj
=
_fake
()
fake_obj
.
data
=
KeyValue
()
form_field
.
populate_obj
(
fake_obj
,
'data'
)
output
[
fake_obj
.
data
.
key
]
=
fake_obj
.
data
.
value
setattr
(
obj
,
name
,
output
)
class
InlineModelFormList
(
InlineFieldList
):
class
InlineModelFormList
(
InlineFieldList
):
"""
"""
Customized inline model form list field.
Customized inline model form list field.
...
...
flask_admin/contrib/sqla/form.py
View file @
d7df4fe4
...
@@ -12,7 +12,9 @@ from flask_admin._backwards import get_property
...
@@ -12,7 +12,9 @@ from flask_admin._backwards import get_property
from
flask_admin._compat
import
iteritems
from
flask_admin._compat
import
iteritems
from
.validators
import
Unique
from
.validators
import
Unique
from
.fields
import
QuerySelectField
,
QuerySelectMultipleField
,
InlineModelFormList
from
.fields
import
(
QuerySelectField
,
QuerySelectMultipleField
,
InlineModelFormList
,
InlineHstoreList
,
HstoreForm
)
from
flask_admin.model.fields
import
InlineFormField
from
.tools
import
has_multiple_pks
,
filter_foreign_columns
from
.tools
import
has_multiple_pks
,
filter_foreign_columns
from
.ajax
import
create_ajax_loader
from
.ajax
import
create_ajax_loader
...
@@ -350,6 +352,11 @@ class AdminModelConverter(ModelConverterBase):
...
@@ -350,6 +352,11 @@ class AdminModelConverter(ModelConverterBase):
def
conv_ARRAY
(
self
,
field_args
,
**
extra
):
def
conv_ARRAY
(
self
,
field_args
,
**
extra
):
return
form
.
Select2TagsField
(
save_as_list
=
True
,
**
field_args
)
return
form
.
Select2TagsField
(
save_as_list
=
True
,
**
field_args
)
@
converts
(
'HSTORE'
)
def
conv_HSTORE
(
self
,
field_args
,
**
extra
):
inner_form
=
field_args
.
pop
(
'form'
,
HstoreForm
)
return
InlineHstoreList
(
InlineFormField
(
inner_form
),
**
field_args
)
def
_resolve_prop
(
prop
):
def
_resolve_prop
(
prop
):
"""
"""
...
...
flask_admin/model/fields.py
View file @
d7df4fe4
...
@@ -40,7 +40,7 @@ class InlineFieldList(FieldList):
...
@@ -40,7 +40,7 @@ class InlineFieldList(FieldList):
def
display_row_controls
(
self
,
field
):
def
display_row_controls
(
self
,
field
):
return
True
return
True
def
process
(
self
,
formdata
,
data
=
Non
e
):
def
process
(
self
,
formdata
,
data
=
unset_valu
e
):
res
=
super
(
InlineFieldList
,
self
)
.
process
(
formdata
,
data
)
res
=
super
(
InlineFieldList
,
self
)
.
process
(
formdata
,
data
)
# Postprocess - contribute flag
# Postprocess - contribute flag
...
...
flask_admin/tests/sqla/__init__.py
View file @
d7df4fe4
...
@@ -14,3 +14,15 @@ def setup():
...
@@ -14,3 +14,15 @@ def setup():
admin
=
Admin
(
app
)
admin
=
Admin
(
app
)
return
app
,
db
,
admin
return
app
,
db
,
admin
def
setup_postgres
():
app
=
Flask
(
__name__
)
app
.
config
[
'SECRET_KEY'
]
=
'1'
app
.
config
[
'CSRF_ENABLED'
]
=
False
app
.
config
[
'SQLALCHEMY_DATABASE_URI'
]
=
'postgresql://localhost/flask_admin_test'
app
.
config
[
'SQLALCHEMY_ECHO'
]
=
True
db
=
SQLAlchemy
(
app
)
admin
=
Admin
(
app
)
return
app
,
db
,
admin
flask_admin/tests/sqla/test_postgres.py
0 → 100644
View file @
d7df4fe4
from
nose.tools
import
eq_
,
ok_
from
.
import
setup_postgres
from
.test_basic
import
CustomModelView
from
sqlalchemy.dialects.postgresql
import
HSTORE
def
test_hstore
():
app
,
db
,
admin
=
setup_postgres
()
class
Model
(
db
.
Model
):
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
,
autoincrement
=
True
)
hstore_test
=
db
.
Column
(
HSTORE
)
db
.
create_all
()
view
=
CustomModelView
(
Model
,
db
.
session
)
admin
.
add_view
(
view
)
client
=
app
.
test_client
()
rv
=
client
.
get
(
'/admin/model/'
)
eq_
(
rv
.
status_code
,
200
)
rv
=
client
.
post
(
'/admin/model/new/'
,
data
=
{
'hstore_test-0-key'
:
'test_val1'
,
'hstore_test-0-value'
:
'test_val2'
})
eq_
(
rv
.
status_code
,
302
)
rv
=
client
.
get
(
'/admin/model/'
)
eq_
(
rv
.
status_code
,
200
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'test_val1'
in
data
)
ok_
(
'test_val2'
in
data
)
rv
=
client
.
get
(
'/admin/model/edit/?id=1'
)
eq_
(
rv
.
status_code
,
200
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'test_val1'
in
data
)
ok_
(
'test_val2'
in
data
)
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