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
39528b9e
Commit
39528b9e
authored
Jul 28, 2013
by
Serge S. Koval
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added FileUploadField and ImageUploadField examples
parent
7962a8ee
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
298 additions
and
1 deletion
+298
-1
.gitignore
.gitignore
+2
-0
README.rst
examples/forms/README.rst
+1
-0
simple.py
examples/forms/simple.py
+131
-0
upload.py
flask_admin/form/upload.py
+5
-1
test_form_upload.py
flask_admin/tests/test_form_upload.py
+159
-0
No files found.
.gitignore
View file @
39528b9e
...
...
@@ -18,3 +18,5 @@ venv
.coverage
__pycache__
examples/sqla-inline/static
examples/file/files
examples/forms/files
examples/forms/README.rst
0 → 100644
View file @
39528b9e
Examples of some Flask-Admin custom WTForms fields and widgets.
\ No newline at end of file
examples/forms/simple.py
0 → 100644
View file @
39528b9e
import
os
import
os.path
as
op
from
flask
import
Flask
,
url_for
from
flask.ext.sqlalchemy
import
SQLAlchemy
from
sqlalchemy.event
import
listens_for
from
jinja2
import
Markup
from
flask.ext.admin
import
Admin
,
form
from
flask.ext.admin.contrib
import
sqla
# Create application
app
=
Flask
(
__name__
,
static_folder
=
'files'
)
# Create dummy secrey key so we can use sessions
app
.
config
[
'SECRET_KEY'
]
=
'123456790'
# Create in-memory database
app
.
config
[
'SQLALCHEMY_DATABASE_URI'
]
=
'sqlite:///test.sqlite'
app
.
config
[
'SQLALCHEMY_ECHO'
]
=
True
db
=
SQLAlchemy
(
app
)
# Create directory for file fields to use
file_path
=
op
.
join
(
op
.
dirname
(
__file__
),
'files'
)
try
:
os
.
mkdir
(
file_path
)
except
OSError
:
pass
# Create models
class
File
(
db
.
Model
):
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
)
name
=
db
.
Column
(
db
.
Unicode
(
64
))
path
=
db
.
Column
(
db
.
Unicode
(
128
))
def
__unicode__
(
self
):
return
self
.
name
class
Image
(
db
.
Model
):
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
)
name
=
db
.
Column
(
db
.
Unicode
(
64
))
path
=
db
.
Column
(
db
.
Unicode
(
128
))
def
__unicode__
(
self
):
return
self
.
name
# Delete hooks for models, delete files if models are getting deleted
@
listens_for
(
File
,
'after_delete'
)
def
del_file
(
mapper
,
connection
,
target
):
if
target
.
path
:
try
:
os
.
remove
(
op
.
join
(
file_path
,
target
.
path
))
except
OSError
:
# Don't care if was not deleted because it does not exist
pass
@
listens_for
(
Image
,
'after_delete'
)
def
del_image
(
mapper
,
connection
,
target
):
if
target
.
path
:
# Delete image
try
:
os
.
remove
(
op
.
join
(
file_path
,
target
.
path
))
except
OSError
:
pass
# Delete thumbnail
try
:
os
.
remove
(
op
.
join
(
file_path
,
form
.
thumbgen_filename
(
target
.
path
)))
except
OSError
:
pass
# Administrative views
class
FileView
(
sqla
.
ModelView
):
# Override form field to use Flask-Admin FileUploadField
form_overrides
=
{
'path'
:
form
.
FileUploadField
}
# Pass additional parameters to 'path' to FileUploadField constructor
form_args
=
{
'path'
:
{
'label'
:
'File'
,
'path'
:
file_path
}
}
class
ImageView
(
sqla
.
ModelView
):
def
_list_thumbnail
(
view
,
context
,
model
,
name
):
if
not
model
.
path
:
return
''
return
Markup
(
'<img src="
%
s">'
%
url_for
(
'static'
,
filename
=
form
.
thumbgen_filename
(
model
.
path
)))
column_formatters
=
{
'path'
:
_list_thumbnail
}
# Alternative way to contribute field is to override it completely.
# In this case, Flask-Admin won't attempt to merge various parameters for the field.
form_extra_fields
=
{
'path'
:
form
.
ImageUploadField
(
'Image'
,
path
=
file_path
)
}
# Flask views
@
app
.
route
(
'/'
)
def
index
():
return
'<a href="/admin/">Click me to get to Admin!</a>'
if
__name__
==
'__main__'
:
# Create admin
admin
=
Admin
(
app
,
'Simple Models'
)
# Add views
admin
.
add_view
(
FileView
(
File
,
db
.
session
))
admin
.
add_view
(
ImageView
(
Image
,
db
.
session
))
# Create DB
db
.
create_all
()
# Start app
app
.
run
(
debug
=
True
)
flask_admin/form/upload.py
View file @
39528b9e
...
...
@@ -45,6 +45,7 @@ class FileUploadInput(object):
def
__call__
(
self
,
field
,
**
kwargs
):
kwargs
.
setdefault
(
'id'
,
field
.
id
)
kwargs
.
setdefault
(
'name'
,
field
.
name
)
template
=
self
.
data_template
if
field
.
data
else
self
.
empty_template
...
...
@@ -72,6 +73,7 @@ class ImageUploadInput(object):
def
__call__
(
self
,
field
,
**
kwargs
):
kwargs
.
setdefault
(
'id'
,
field
.
id
)
kwargs
.
setdefault
(
'name'
,
field
.
name
)
args
=
{
'file'
:
html_params
(
type
=
'file'
,
...
...
@@ -138,6 +140,8 @@ class FileUploadField(fields.TextField):
self
.
_delete_file
(
field
)
return
print
field
,
type
(
self
.
data
)
if
isinstance
(
self
.
data
,
FileStorage
):
if
field
:
self
.
_delete_file
(
field
)
...
...
@@ -169,7 +173,7 @@ class ImageUploadField(FileUploadField):
raise
Exception
(
'PIL library was not found'
)
self
.
thumbnail_fn
=
thumbgen
or
thumbgen_filename
self
.
thumbnail_size
=
thumbnail_size
self
.
thumbnail_size
=
thumbnail_size
or
(
128
,
128
,
True
)
self
.
endpoint
=
endpoint
self
.
image
=
None
...
...
flask_admin/tests/test_form_upload.py
0 → 100644
View file @
39528b9e
import
os
import
os.path
as
op
from
StringIO
import
StringIO
from
nose.tools
import
eq_
,
ok_
from
flask
import
Flask
from
flask.ext.admin
import
form
,
helpers
def
_create_temp
():
path
=
op
.
join
(
op
.
dirname
(
__file__
),
'tmp'
)
if
not
op
.
exists
(
path
):
os
.
mkdir
(
path
)
return
path
def
safe_delete
(
path
,
name
):
try
:
os
.
remove
(
op
.
join
(
path
,
name
))
except
:
pass
def
test_upload_field
():
app
=
Flask
(
__name__
)
path
=
_create_temp
()
def
_remove_testfiles
():
safe_delete
(
path
,
'test1.txt'
)
safe_delete
(
path
,
'test2.txt'
)
class
TestForm
(
form
.
BaseForm
):
upload
=
form
.
FileUploadField
(
'Upload'
,
path
=
path
)
class
Dummy
(
object
):
pass
my_form
=
TestForm
()
eq_
(
my_form
.
upload
.
path
,
path
)
_remove_testfiles
()
dummy
=
Dummy
()
# Check upload
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'upload'
:
(
StringIO
(
'Hello World'
),
'test1.txt'
)}):
my_form
=
TestForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
eq_
(
dummy
.
upload
,
'test1.txt'
)
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test1.txt'
)))
# Check replace
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'upload'
:
(
StringIO
(
'Hello World'
),
'test2.txt'
)}):
my_form
=
TestForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
eq_
(
dummy
.
upload
,
'test2.txt'
)
ok_
(
not
op
.
exists
(
op
.
join
(
path
,
'test1.txt'
)))
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test2.txt'
)))
# Check delete
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'_upload-delete'
:
'checked'
}):
my_form
=
TestForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
ok_
(
not
op
.
exists
(
op
.
join
(
path
,
'test2.txt'
)))
def
test_image_upload_field
():
app
=
Flask
(
__name__
)
path
=
_create_temp
()
def
_remove_testimages
():
safe_delete
(
path
,
'test1.png'
)
safe_delete
(
path
,
'test1_thumb.jpg'
)
safe_delete
(
path
,
'test2.png'
)
safe_delete
(
path
,
'test2_thumb.jpg'
)
class
TestForm
(
form
.
BaseForm
):
upload
=
form
.
ImageUploadField
(
'Upload'
,
path
=
path
,
thumbnail_size
=
(
100
,
100
,
True
))
class
TestNoResizeForm
(
form
.
BaseForm
):
upload
=
form
.
ImageUploadField
(
'Upload'
,
path
=
path
)
class
Dummy
(
object
):
pass
my_form
=
TestForm
()
eq_
(
my_form
.
upload
.
path
,
path
)
eq_
(
my_form
.
upload
.
endpoint
,
'static'
)
_remove_testimages
()
dummy
=
Dummy
()
# Check upload
with
file
(
op
.
join
(
op
.
dirname
(
__file__
),
'data'
,
'copyleft.png'
),
'rb'
)
as
fp
:
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'upload'
:
(
fp
,
'test1.png'
)}):
my_form
=
TestForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
eq_
(
dummy
.
upload
,
'test1.png'
)
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test1.png'
)))
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test1_thumb.jpg'
)))
# Check replace
with
file
(
op
.
join
(
op
.
dirname
(
__file__
),
'data'
,
'copyleft.png'
),
'rb'
)
as
fp
:
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'upload'
:
(
fp
,
'test2.png'
)}):
my_form
=
TestForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
eq_
(
dummy
.
upload
,
'test2.png'
)
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test2.png'
)))
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test2_thumb.jpg'
)))
ok_
(
not
op
.
exists
(
op
.
join
(
path
,
'test1.png'
)))
ok_
(
not
op
.
exists
(
op
.
join
(
path
,
'test1_thumb.jpg'
)))
# Check delete
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'_upload-delete'
:
'checked'
}):
my_form
=
TestForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
ok_
(
not
op
.
exists
(
op
.
join
(
path
,
'test2.png'
)))
ok_
(
not
op
.
exists
(
op
.
join
(
path
,
'test2_thumb.jpg'
)))
# Check upload no-resize
with
file
(
op
.
join
(
op
.
dirname
(
__file__
),
'data'
,
'copyleft.png'
),
'rb'
)
as
fp
:
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'upload'
:
(
fp
,
'test1.png'
)}):
my_form
=
TestNoResizeForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
eq_
(
dummy
.
upload
,
'test1.png'
)
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test1.png'
)))
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test1_thumb.jpg'
)))
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