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
fba71aef
Commit
fba71aef
authored
Jul 30, 2013
by
Serge S. Koval
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added relative_path to upload fields. Fixes #269
parent
99f09f5b
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
96 additions
and
24 deletions
+96
-24
upload.py
flask_admin/form/upload.py
+47
-18
test_form_upload.py
flask_admin/tests/test_form_upload.py
+49
-6
No files found.
flask_admin/form/upload.py
View file @
fba71aef
import
os
import
os.path
as
op
import
logging
from
urlparse
import
urljoin
from
flask
import
url_for
...
...
@@ -86,8 +86,12 @@ class ImageUploadInput(object):
}
if
field
.
data
and
isinstance
(
field
.
data
,
string_types
):
args
[
'image'
]
=
html_params
(
src
=
url_for
(
field
.
endpoint
,
filename
=
field
.
thumbnail_fn
(
field
.
data
)))
if
field
.
thumbnail_size
:
url
=
url_for
(
field
.
endpoint
,
filename
=
field
.
thumbnail_fn
(
field
.
data
))
else
:
url
=
url_for
(
field
.
endpoint
,
filename
=
field
.
data
)
args
[
'image'
]
=
html_params
(
src
=
url
)
template
=
self
.
data_template
else
:
...
...
@@ -107,7 +111,8 @@ class FileUploadField(fields.TextField):
widget
=
FileUploadInput
()
def
__init__
(
self
,
label
=
None
,
validators
=
None
,
path
=
None
,
namegen
=
None
,
allowed_extensions
=
None
,
base_path
=
None
,
relative_path
=
None
,
namegen
=
None
,
allowed_extensions
=
None
,
**
kwargs
):
"""
Constructor.
...
...
@@ -116,8 +121,12 @@ class FileUploadField(fields.TextField):
Display label
:param validators:
Validators
:param path:
Full path to the directory which will store files
:param base_path:
Absolute path to the directory which will store files
:param relative_path:
Relative path from the directory. Will be prepended to the file name for uploaded files.
Flask-Admin uses `urlparse.urljoin` to generate resulting filename, so make sure you have
trailing slash.
:param namegen:
Function that will generate filename from the model and uploaded file object.
Please note, that model is "dirty" model object, before it was committed to database.
...
...
@@ -136,10 +145,12 @@ class FileUploadField(fields.TextField):
:param allowed_extensions:
List of allowed extensions. If not provided, will allow any file.
"""
if
not
path
:
if
not
base_
path
:
raise
ValueError
(
'FileUploadField field requires target path.'
)
self
.
path
=
path
self
.
base_path
=
base_path
self
.
relative_path
=
relative_path
self
.
namegen
=
namegen
or
namegen_filename
self
.
allowed_extensions
=
allowed_extensions
self
.
_should_delete
=
False
...
...
@@ -186,19 +197,31 @@ class FileUploadField(fields.TextField):
if
field
:
self
.
_delete_file
(
field
)
filename
=
self
.
namegen
(
obj
,
self
.
data
)
filename
=
self
.
generate_name
(
obj
,
self
.
data
)
self
.
_save_file
(
self
.
data
,
filename
)
setattr
(
obj
,
name
,
filename
)
def
generate_name
(
self
,
obj
,
file_data
):
filename
=
self
.
namegen
(
obj
,
file_data
)
if
not
self
.
relative_path
:
return
filename
return
urljoin
(
self
.
relative_path
,
filename
)
def
_get_path
(
self
,
filename
):
return
op
.
join
(
self
.
base_path
,
filename
)
def
_delete_file
(
self
,
filename
):
path
=
op
.
join
(
self
.
path
,
filename
)
path
=
self
.
_get_path
(
filename
)
if
op
.
exists
(
path
):
os
.
remove
(
path
)
def
_save_file
(
self
,
data
,
filename
):
data
.
save
(
op
.
join
(
self
.
path
,
filename
))
path
=
self
.
_get_path
(
filename
)
data
.
save
(
path
)
class
ImageUploadField
(
FileUploadField
):
...
...
@@ -212,7 +235,8 @@ class ImageUploadField(FileUploadField):
widget
=
ImageUploadInput
()
def
__init__
(
self
,
label
=
None
,
validators
=
None
,
path
=
None
,
namegen
=
None
,
allowed_extensions
=
None
,
base_path
=
None
,
relative_path
=
None
,
namegen
=
None
,
allowed_extensions
=
None
,
thumbgen
=
None
,
thumbnail_size
=
None
,
endpoint
=
'static'
,
**
kwargs
):
"""
...
...
@@ -222,8 +246,12 @@ class ImageUploadField(FileUploadField):
Display label
:param validators:
Validators
:param path:
Full path to the directory which will store files
:param base_path:
Absolute path to the directory which will store files
:param relative_path:
Relative path from the directory. Will be prepended to the file name for uploaded files.
Flask-Admin uses `urlparse.urljoin` to generate resulting filename, so make sure you have
trailing slash.
:param namegen:
Function that will generate filename from the model and uploaded file object.
Please note, that model is "dirty" model object, before it was committed to database.
...
...
@@ -277,7 +305,8 @@ class ImageUploadField(FileUploadField):
allowed_extensions
=
(
'gif'
,
'jpg'
,
'jpeg'
,
'png'
)
super
(
ImageUploadField
,
self
)
.
__init__
(
label
,
validators
,
path
=
path
,
base_path
=
base_path
,
relative_path
=
relative_path
,
namegen
=
namegen
,
allowed_extensions
=
allowed_extensions
,
**
kwargs
)
...
...
@@ -298,14 +327,14 @@ class ImageUploadField(FileUploadField):
self
.
_delete_thumbnail
(
filename
)
def
_delete_thumbnail
(
self
,
filename
):
path
=
op
.
join
(
self
.
path
,
self
.
thumbnail_fn
(
filename
))
path
=
self
.
_get_path
(
self
.
thumbnail_fn
(
filename
))
if
op
.
exists
(
path
):
os
.
remove
(
path
)
# Saving
def
_save_file
(
self
,
data
,
filename
):
data
.
save
(
op
.
join
(
self
.
path
,
filename
))
data
.
save
(
self
.
_get_path
(
filename
))
self
.
_save_thumbnail
(
data
,
filename
)
...
...
@@ -321,7 +350,7 @@ class ImageUploadField(FileUploadField):
else
:
thumb
=
self
.
image
.
copy
()
.
thumbnail
((
width
,
height
),
Image
.
ANTIALIAS
)
path
=
op
.
join
(
self
.
path
,
self
.
thumbnail_fn
(
filename
))
path
=
self
.
_get_path
(
self
.
thumbnail_fn
(
filename
))
with
open
(
path
,
'wb'
)
as
fp
:
thumb
.
save
(
fp
,
'JPEG'
)
...
...
flask_admin/tests/test_form_upload.py
View file @
fba71aef
...
...
@@ -5,7 +5,7 @@ from io import BytesIO
from
nose.tools
import
eq_
,
ok_
from
flask
import
Flask
from
flask
import
Flask
,
url_for
from
flask.ext.admin
import
form
,
helpers
...
...
@@ -13,6 +13,11 @@ def _create_temp():
path
=
op
.
join
(
op
.
dirname
(
__file__
),
'tmp'
)
if
not
op
.
exists
(
path
):
os
.
mkdir
(
path
)
inner
=
op
.
join
(
path
,
'inner'
)
if
not
op
.
exists
(
inner
):
os
.
mkdir
(
inner
)
return
path
...
...
@@ -33,13 +38,13 @@ def test_upload_field():
safe_delete
(
path
,
'test2.txt'
)
class
TestForm
(
form
.
BaseForm
):
upload
=
form
.
FileUploadField
(
'Upload'
,
path
=
path
)
upload
=
form
.
FileUploadField
(
'Upload'
,
base_
path
=
path
)
class
Dummy
(
object
):
pass
my_form
=
TestForm
()
eq_
(
my_form
.
upload
.
path
,
path
)
eq_
(
my_form
.
upload
.
base_
path
,
path
)
_remove_testfiles
()
...
...
@@ -91,16 +96,18 @@ def test_image_upload_field():
safe_delete
(
path
,
'test2_thumb.jpg'
)
class
TestForm
(
form
.
BaseForm
):
upload
=
form
.
ImageUploadField
(
'Upload'
,
path
=
path
,
thumbnail_size
=
(
100
,
100
,
True
))
upload
=
form
.
ImageUploadField
(
'Upload'
,
base_path
=
path
,
thumbnail_size
=
(
100
,
100
,
True
))
class
TestNoResizeForm
(
form
.
BaseForm
):
upload
=
form
.
ImageUploadField
(
'Upload'
,
path
=
path
)
upload
=
form
.
ImageUploadField
(
'Upload'
,
base_path
=
path
,
endpoint
=
'test'
)
class
Dummy
(
object
):
pass
my_form
=
TestForm
()
eq_
(
my_form
.
upload
.
path
,
path
)
eq_
(
my_form
.
upload
.
base_
path
,
path
)
eq_
(
my_form
.
upload
.
endpoint
,
'static'
)
_remove_testimages
()
...
...
@@ -162,3 +169,39 @@ def test_image_upload_field():
eq_
(
dummy
.
upload
,
'test1.png'
)
ok_
(
op
.
exists
(
op
.
join
(
path
,
'test1.png'
)))
ok_
(
not
op
.
exists
(
op
.
join
(
path
,
'test1_thumb.jpg'
)))
def
test_relative_path
():
app
=
Flask
(
__name__
)
path
=
_create_temp
()
def
_remove_testfiles
():
safe_delete
(
path
,
'test1.txt'
)
class
TestForm
(
form
.
BaseForm
):
upload
=
form
.
FileUploadField
(
'Upload'
,
base_path
=
path
,
relative_path
=
'inner/'
)
class
Dummy
(
object
):
pass
my_form
=
TestForm
()
eq_
(
my_form
.
upload
.
base_path
,
path
)
eq_
(
my_form
.
upload
.
relative_path
,
'inner/'
)
_remove_testfiles
()
dummy
=
Dummy
()
# Check upload
with
app
.
test_request_context
(
method
=
'POST'
,
data
=
{
'upload'
:
(
BytesIO
(
b
'Hello World 1'
),
'test1.txt'
)}):
my_form
=
TestForm
(
helpers
.
get_form_data
())
ok_
(
my_form
.
validate
())
my_form
.
populate_obj
(
dummy
)
eq_
(
dummy
.
upload
,
'inner/test1.txt'
)
ok_
(
op
.
exists
(
op
.
join
(
path
,
'inner/test1.txt'
)))
eq_
(
url_for
(
'static'
,
filename
=
dummy
.
upload
),
'/static/inner/test1.txt'
)
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