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
d2b6f20a
Commit
d2b6f20a
authored
Aug 25, 2013
by
Florian Sachs
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'upstream/master'
parents
57ff13b7
79f4f907
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
71 additions
and
41 deletions
+71
-41
db_sqla.rst
doc/db_sqla.rst
+7
-8
__init__.py
flask_admin/contrib/mongoengine/__init__.py
+1
-0
form.py
flask_admin/contrib/mongoengine/form.py
+9
-7
view.py
flask_admin/contrib/mongoengine/view.py
+5
-6
form.py
flask_admin/contrib/sqla/form.py
+5
-5
upload.py
flask_admin/form/upload.py
+14
-5
fields.py
flask_admin/model/fields.py
+20
-0
form.py
flask_admin/model/form.py
+6
-6
form.js
flask_admin/static/admin/js/form.js
+1
-1
inline_form.html
flask_admin/templates/admin/model/inline_form.html
+1
-1
test_basic.py
flask_admin/tests/mongoengine/test_basic.py
+2
-2
No files found.
doc/db_sqla.rst
View file @
d2b6f20a
...
...
@@ -106,10 +106,11 @@ configuration properties and methods.
Multiple Primary Keys
---------------------
Models with multiple primary keys have limited support, as a few pitfalls are waiting for you.
With using multiple primary keys, weak entities can be used with Flask-Admin.
Flask-Admin has limited support for models with multiple primary keys. It only covers specific case when
all but one primary keys are foreign keys to another model. For example, model inheritance following
this convention.
Lets Model a car with it
'
s tyres::
Lets Model a car with its tyres::
class Car(db.Model):
__tablename__ = 'cars'
...
...
@@ -129,19 +130,17 @@ Lets Model a car with it's tyres::
A specific tyre is identified by using the two primary key columns of the ``Tyre`` class, of which the ``car_id`` key
is itself a foreign key to the class ``Car``.
To be able to CRUD the ``Tyre`` class,
two steps are necessary, when defini
g the AdminView::
To be able to CRUD the ``Tyre`` class,
you need to enumerate columns when definin
g the AdminView::
class TyreAdmin(sqla.ModelView):
form_columns = ['car', 'tyre_id', 'desc']
The ``form_columns`` needs to be explizit, as per default only one primary key is displayed. When, like in this
example, one part of the key is a foreign key, do not include the foreign-key-columns here, but the
corresponding relationship.
The ``form_columns`` needs to be explicit, as per default only one primary key is displayed.
When having multiple primary keys, **no** validation for uniqueness *prior* to saving of the object will be done. Saving
a model that violates a unique-constraint leads to an Sqlalchemy-Integrity-Error. In this case, ``Flask-Admin`` displays
a proper error message and you can change the data in the form. When the application has been started with ``debug=True``
the ``werkzeug`` debugger
catches the exception and displays
the stacktrace.
the ``werkzeug`` debugger
will catch the exception and will display
the stacktrace.
A standalone script with the Examples from above can be found in the examples directory.
...
...
flask_admin/contrib/mongoengine/__init__.py
View file @
d2b6f20a
...
...
@@ -4,3 +4,4 @@ except ImportError:
raise
Exception
(
'Please install flask-mongoengine in order to use mongoengine backend'
)
from
.view
import
ModelView
from
.form
import
EmbeddedForm
flask_admin/contrib/mongoengine/form.py
View file @
d2b6f20a
...
...
@@ -7,7 +7,7 @@ from wtforms import fields, validators
from
flask.ext.mongoengine.wtf
import
orm
,
fields
as
mongo_fields
from
flask.ext.admin
import
form
from
flask.ext.admin.model.form
import
FieldPlaceholder
,
InlineFormAdmin
from
flask.ext.admin.model.form
import
FieldPlaceholder
,
Inline
Base
FormAdmin
from
flask.ext.admin.model.fields
import
InlineFieldList
from
flask.ext.admin.model.widgets
import
InlineFormWidget
from
flask.ext.admin._compat
import
iteritems
...
...
@@ -15,6 +15,10 @@ from flask.ext.admin._compat import iteritems
from
.fields
import
ModelFormField
,
MongoFileField
,
MongoImageField
class
EmbeddedForm
(
InlineBaseFormAdmin
):
pass
class
CustomModelConverter
(
orm
.
ModelConverter
):
"""
Customized MongoEngine form conversion class.
...
...
@@ -39,18 +43,16 @@ class CustomModelConverter(orm.ModelConverter):
def
_get_subdocument_config
(
self
,
name
):
config
=
getattr
(
self
.
view
,
'form_subdocuments'
,
{})
print
'x'
,
name
,
config
p
=
config
.
get
(
name
)
if
not
p
:
return
InlineFormAdmin
()
return
EmbeddedForm
()
if
isinstance
(
p
,
dict
):
return
InlineFormAdmin
(
**
p
)
elif
isinstance
(
p
,
InlineFormAdmin
):
return
EmbeddedForm
(
**
p
)
elif
isinstance
(
p
,
EmbeddedForm
):
return
p
raise
ValueError
(
'Invalid subdocument type: expecting dict or instance of
InlineFormAdmin
, got
%
s'
%
type
(
p
))
raise
ValueError
(
'Invalid subdocument type: expecting dict or instance of
flask.ext.admin.contrib.mongoengine.EmbeddedForm
, got
%
s'
%
type
(
p
))
def
clone_converter
(
self
,
view
):
return
self
.
__class__
(
view
)
...
...
flask_admin/contrib/mongoengine/view.py
View file @
d2b6f20a
...
...
@@ -9,7 +9,6 @@ from flask.ext.admin._compat import iteritems, string_types
import
mongoengine
import
gridfs
from
mongoengine.fields
import
GridFSProxy
,
ImageGridFsProxy
from
mongoengine.connection
import
get_db
from
bson.objectid
import
ObjectId
...
...
@@ -98,12 +97,12 @@ class ModelView(BaseModelView):
List of allowed search field types.
"""
form_subdocuments
=
None
form_subdocuments
=
{}
"""
Subdocument configuration options.
This field accepts dictionary, where key is field name and value is either dictionary or instance of the
`
InlineFormAdmin
`.
`
flask.ext.admin.contrib.EmbeddedForm
`.
Consider following example::
...
...
@@ -127,7 +126,7 @@ class ModelView(BaseModelView):
It is also possible to use class-based embedded document configuration:
class CommentEmbed(
InlineFormAdmin
):
class CommentEmbed(
EmbeddedForm
):
form_columns = ('name',)
class MyAdmin(ModelView):
...
...
@@ -137,10 +136,10 @@ class ModelView(BaseModelView):
Arbitrary depth nesting is supported::
class SomeEmbed(
InlineFormAdmin
):
class SomeEmbed(
EmbeddedForm
):
form_excluded_columns = ('test',)
class CommentEmbed(
InlineFormAdmin
):
class CommentEmbed(
EmbeddedForm
):
form_columns = ('name',)
form_subdocuments = {
'inner': SomeEmbed()
...
...
flask_admin/contrib/sqla/form.py
View file @
d2b6f20a
...
...
@@ -4,7 +4,7 @@ from sqlalchemy import Boolean, Column
from
flask.ext.admin
import
form
from
flask.ext.admin.form
import
Select2Field
from
flask.ext.admin.model.form
import
(
converts
,
ModelConverterBase
,
Inline
Model
FormAdmin
,
InlineModelConverterBase
,
InlineFormAdmin
,
InlineModelConverterBase
,
FieldPlaceholder
)
from
flask.ext.admin.model.helpers
import
prettify_name
from
flask.ext.admin._backwards
import
get_property
...
...
@@ -439,7 +439,7 @@ class InlineModelConverter(InlineModelConverterBase):
Flask-Admin view object
:param model_converter:
Model converter class. Will be automatically instantiated with
appropriate `Inline
Model
FormAdmin` instance.
appropriate `InlineFormAdmin` instance.
"""
super
(
InlineModelConverter
,
self
)
.
__init__
(
view
)
self
.
session
=
session
...
...
@@ -451,7 +451,7 @@ class InlineModelConverter(InlineModelConverterBase):
# Special case for model instances
if
info
is
None
:
if
hasattr
(
p
,
'_sa_class_manager'
):
return
Inline
Model
FormAdmin
(
p
)
return
InlineFormAdmin
(
p
)
else
:
model
=
getattr
(
p
,
'model'
,
None
)
...
...
@@ -463,9 +463,9 @@ class InlineModelConverter(InlineModelConverterBase):
if
not
attr
.
startswith
(
'_'
)
and
attr
!=
'model'
:
attrs
[
attr
]
=
getattr
(
p
,
attr
)
return
Inline
Model
FormAdmin
(
model
,
**
attrs
)
return
InlineFormAdmin
(
model
,
**
attrs
)
info
=
Inline
Model
FormAdmin
(
model
,
**
attrs
)
info
=
InlineFormAdmin
(
model
,
**
attrs
)
return
info
...
...
flask_admin/form/upload.py
View file @
d2b6f20a
...
...
@@ -21,7 +21,6 @@ except ImportError:
Image
=
None
ImageOps
=
None
__all__
=
[
'FileUploadInput'
,
'FileUploadField'
,
'ImageUploadInput'
,
'ImageUploadField'
,
'namegen_filename'
,
'thumbgen_filename'
]
...
...
@@ -103,8 +102,6 @@ class ImageUploadInput(object):
if
field
.
url_relative_path
:
filename
=
urljoin
(
field
.
url_relative_path
,
filename
)
return
url_for
(
field
.
endpoint
,
filename
)
return
url_for
(
field
.
endpoint
,
filename
=
field
.
data
)
...
...
@@ -229,6 +226,9 @@ class FileUploadField(fields.TextField):
def
_save_file
(
self
,
data
,
filename
):
path
=
self
.
_get_path
(
filename
)
if
not
op
.
exists
(
op
.
dirname
(
path
)):
os
.
makedirs
(
os
.
path
.
dirname
(
path
),
0o666
)
data
.
save
(
path
)
return
filename
...
...
@@ -328,6 +328,7 @@ class ImageUploadField(FileUploadField):
self
.
thumbnail_size
=
thumbnail_size
self
.
endpoint
=
endpoint
self
.
image
=
None
self
.
url_relative_path
=
url_relative_path
if
not
allowed_extensions
:
allowed_extensions
=
(
'gif'
,
'jpg'
,
'jpeg'
,
'png'
,
'tiff'
)
...
...
@@ -362,6 +363,10 @@ class ImageUploadField(FileUploadField):
# Saving
def
_save_file
(
self
,
data
,
filename
):
path
=
self
.
_get_path
(
filename
)
if
not
op
.
exists
(
op
.
dirname
(
path
)):
os
.
makedirs
(
os
.
path
.
dirname
(
path
),
0o666
)
if
self
.
image
and
self
.
max_size
:
filename
,
format
=
self
.
_get_save_format
(
filename
,
self
.
image
)
...
...
@@ -369,7 +374,8 @@ class ImageUploadField(FileUploadField):
self
.
_get_path
(
filename
),
format
)
else
:
data
.
save
(
self
.
_get_path
(
filename
))
data
.
seek
(
0
)
data
.
save
(
path
)
self
.
_save_thumbnail
(
data
,
filename
)
...
...
@@ -389,11 +395,14 @@ class ImageUploadField(FileUploadField):
if
force
:
return
ImageOps
.
fit
(
self
.
image
,
(
width
,
height
),
Image
.
ANTIALIAS
)
else
:
return
self
.
image
.
copy
()
.
thumbnail
((
width
,
height
),
Image
.
ANTIALIAS
)
thumb
=
self
.
image
.
copy
()
thumb
.
thumbnail
((
width
,
height
),
Image
.
ANTIALIAS
)
return
thumb
return
image
def
_save_image
(
self
,
image
,
path
,
format
=
'JPEG'
):
image
=
image
.
convert
(
'RGB'
)
with
open
(
path
,
'wb'
)
as
fp
:
image
.
save
(
fp
,
format
)
...
...
flask_admin/model/fields.py
View file @
d2b6f20a
...
...
@@ -41,6 +41,26 @@ class InlineFieldList(FieldList):
return
res
def
validate
(
self
,
form
,
extra_validators
=
tuple
()):
"""
Validate this FieldList.
Note that FieldList validation differs from normal field validation in
that FieldList validates all its enclosed fields first before running any
of its own validators.
"""
self
.
errors
=
[]
# Run validators on all entries within
for
subfield
in
self
.
entries
:
if
not
self
.
should_delete
(
subfield
)
and
not
subfield
.
validate
(
form
):
self
.
errors
.
append
(
subfield
.
errors
)
chain
=
itertools
.
chain
(
self
.
validators
,
extra_validators
)
self
.
_run_validation_chain
(
form
,
chain
)
return
len
(
self
.
errors
)
==
0
def
should_delete
(
self
,
field
):
return
getattr
(
field
,
'_should_delete'
,
False
)
...
...
flask_admin/model/form.py
View file @
d2b6f20a
...
...
@@ -11,14 +11,14 @@ def converts(*args):
return
_inner
class
InlineFormAdmin
(
object
):
class
Inline
Base
FormAdmin
(
object
):
"""
Settings for inline form administration.
You can use this class to customize displayed form.
For example::
class MyUserInfoForm(InlineFormAdmin):
class MyUserInfoForm(Inline
Base
FormAdmin):
form_columns = ('name', 'email')
"""
_defaults
=
[
'form_base_class'
,
'form_columns'
,
'form_excluded_columns'
,
'form_args'
,
'form_extra_fields'
]
...
...
@@ -72,7 +72,7 @@ class InlineFormAdmin(object):
pass
class
Inline
ModelFormAdmin
(
Inlin
eFormAdmin
):
class
Inline
FormAdmin
(
InlineBas
eFormAdmin
):
"""
Settings for inline form administration. Used by relational backends (SQLAlchemy, Peewee), where model
class can not be inherited from the parent model definition.
...
...
@@ -86,7 +86,7 @@ class InlineModelFormAdmin(InlineFormAdmin):
"""
self
.
model
=
model
super
(
Inline
Model
FormAdmin
,
self
)
.
__init__
(
**
kwargs
)
super
(
InlineFormAdmin
,
self
)
.
__init__
(
**
kwargs
)
class
ModelConverterBase
(
object
):
...
...
@@ -173,8 +173,8 @@ class InlineModelConverterBase(object):
- Model class
"""
if
isinstance
(
p
,
tuple
):
return
Inline
Model
FormAdmin
(
p
[
0
],
**
p
[
1
])
elif
isinstance
(
p
,
Inline
Model
FormAdmin
):
return
InlineFormAdmin
(
p
[
0
],
**
p
[
1
])
elif
isinstance
(
p
,
InlineFormAdmin
):
return
p
return
None
...
...
flask_admin/static/admin/js/form.js
View file @
d2b6f20a
...
...
@@ -63,7 +63,7 @@
this
.
applyGlobalStyles
=
function
(
parent
)
{
$
(
'[data-role=select2]'
,
parent
).
select2
({
width
:
'resolve'
});
$
(
'[data-role=select2blank]'
,
parent
).
select2
({
allowClear
:
true
,
width
:
'resolve'
});
$
(
'[data-role=select2tags]'
,
parent
).
select2
({
tags
:
[]
,
tokenSeparators
:
[
','
],
width
:
'resolve'
});
$
(
'[data-role=select2tags]'
,
parent
).
select2
({
multiple
:
true
,
tokenSeparators
:
[
','
],
width
:
'resolve'
});
$
(
'[data-role=datepicker]'
,
parent
).
datepicker
();
$
(
'[data-role=datetimepicker]'
,
parent
).
datepicker
({
displayTime
:
true
});
};
...
...
flask_admin/templates/admin/model/inline_form.html
View file @
d2b6f20a
{% import 'admin/lib.html' as lib with context %}
<div
class=
"
inline-form
"
>
<div
class=
"
fa-inline-field
"
>
{{ lib.render_form_fields(field, False) }}
</div>
flask_admin/tests/mongoengine/test_basic.py
View file @
d2b6f20a
...
...
@@ -259,7 +259,7 @@ def test_subdocument_config():
def
test_subdocument_class_config
():
app
,
db
,
admin
=
setup
()
from
flask.ext.admin.
model.form
import
InlineFormAdmin
from
flask.ext.admin.
contrib.mongoengine
import
EmbeddedForm
class
Comment
(
db
.
EmbeddedDocument
):
name
=
db
.
StringField
(
max_length
=
20
,
required
=
True
)
...
...
@@ -269,7 +269,7 @@ def test_subdocument_class_config():
test1
=
db
.
StringField
(
max_length
=
20
)
subdoc
=
db
.
EmbeddedDocumentField
(
Comment
)
class
EmbeddedConfig
(
InlineFormAdmin
):
class
EmbeddedConfig
(
EmbeddedForm
):
form_columns
=
(
'name'
,)
# Check only
...
...
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