Extends SQLAlchemy to support and mostly identify a Image Column
+class flask.ext.appbuilder.models.mixins.ImageColumn(thumbnail_size=(20, 20, True), size=(100, 100, True), **kw)¶ +Extends SQLAlchemy to support and mostly identify an Image Column
You can implement views with images or files embedded on the model’s definition
+You can implement views with images or files embedded on the model’s definition. You can do it using SQLAlchemy or +MongoDB (MongoEngine). When using SQLAlchemy, files and images are saved on the filesystem, on MongoDB on the db (GridFS).
Create an additional method in this case photo_img, to inject your own custom HTML, to show your saved images. In this example the customized method is showing the images, and linking them with the show view.
-Later reference this method like it’s a column on your view.
+Create two additional methods in this case photo_img and photo_img_thumbnail, to inject your own custom HTML, +to show your saved images. In this example the customized method is showing the images, and linking them with the show view. +Notice how the methods are calling get_url and get_url_thumbnail from ImageManager, these are returning the +url for the images, each image is saved on the filesystem using the global config IMG_UPLOAD_FOLDER. +Each image will have two files with different sizes, images are saved as <uuid>_sep_<filename>, and <uuid>_sep_<filename>_thumb
Note
The “ImageColumn” type, is an extended type from Flask-AppBuilder.
Later reference this method like it’s a column on your view.
+To implement image or file support using GridFS from MongoDB is even easier, take a look at the example:
+https://github.com/dpgaspar/Flask-AppBuilder/tree/master/examples/mongoimages
Notice that we are overriding the list_widget, the widget that is normally used by ModelView. This will display a thumbnail list, excellent for displaying images.
-We are not using the image column but the method photo_img we have created. This method will display the image and link it to the show view.
-And that’s it! images will be saved on the server. Their file names will result in the concatenation of UUID with their original name. They will be resized for optimization.
+We are overriding the list_widget, the widget that is normally used by ModelView. +This will display a thumbnail list, excellent for displaying images.
+We’re not using the image column but the methods photo_img and photo_img_thumbnail we have created. +These methods will display the images and link them to show view.
+And that’s it! images will be saved on the server. +Their file names will result in the concatenation of UUID with their original name. They will be resized for optimization.
Note
You can define image resizing using configuration key IMG_SIZE
diff --git a/docs/_build/html/quickhowto.html b/docs/_build/html/quickhowto.html index 801b7e3fa..c3b0a61e6 100644 --- a/docs/_build/html/quickhowto.html +++ b/docs/_build/html/quickhowto.html @@ -24,7 +24,7 @@ - + @@ -45,7 +45,7 @@There are some breaking features:
-1 - Security models have changed, user’s can have multiple roles, not just one. So you have to migrate you db.
+1 - Security models have changed, user’s can have multiple roles, not just one. So you have to upgrade your db.
The security models schema have changed.
-If you are using sqlite, mysql or pgsql, use the following procedure:
+If you are using sqlite, mysql, pgsql, mssql or oracle, use the following procedure:
1 - Backup your DB.
2 - If you haven’t already, upgrade to flask-appbuilder 1.3.0.
3 - Issue the following commands, on your project folder where config.py exists:
-cd /your-main-project-folder/ -wget https://raw.github.com/dpgaspar/Flask-AppBuilder/master/bin/migrate_db_1.3.py -python migrate_db_1.3.py +$ cd /your-main-project-folder/ +$ fabmanager upgrade-db4 - Test and Run (if you have a run.py for development)
-diff --git a/docs/_build/html/versions.html b/docs/_build/html/versions.html index 5ba8882d8..014ac469d 100644 --- a/docs/_build/html/versions.html +++ b/docs/_build/html/versions.html @@ -78,10 +78,10 @@-python run.py +$ fabmanager runIf not (DB is not sqlite, mysql or pgsql), you will have to alter the schema your self. use the following procedure:
--+1 - Backup your DB.
-2 - If you haven’t already, upgrade to flask-appbuilder 0.7.0.
-3 - issue the corresponding DDL commands to:
-ALTER TABLE ab_user MODIFY COLUMN password VARCHAR(256)
-For sqlite you’ll have to drop role_id columns and FK yourself. follow the script instructions to finish the upgrade.
Improvements and Bug fixes on 1.3.0 diff --git a/docs/quickfiles.rst b/docs/quickfiles.rst index 7c5983520..d37f8f8de 100644 --- a/docs/quickfiles.rst +++ b/docs/quickfiles.rst @@ -2,7 +2,7 @@ Model Views with Files and Images ================================= You can implement views with images or files embedded on the model's definition. You can do it using SQLAlchemy or -MongoDB (MongoEngine). When using SQLAlchemy files and images are saved on the filesystem, on MongoDB on the db. +MongoDB (MongoEngine). When using SQLAlchemy, files and images are saved on the filesystem, on MongoDB on the db (GridFS). Define your model (models.py) ----------------------------- @@ -15,22 +15,44 @@ Define your model (models.py) class Person(Model): id = Column(Integer, primary_key=True) name = Column(String(150), unique = True, nullable=False) - photo = Column(ImageColumn, nullable=False ) + photo = Column(ImageColumn(size=(300, 300, True), thumbnail_size=(30, 30, True))) def photo_img(self): im = ImageManager() if self.photo: - return Markup('') + return Markup('') else: - return Markup('') - -Create an additional method in this case *photo_img*, to inject your own custom HTML, to show your saved images. In this example the customized method is showing the images, and linking them with the show view. + return Markup('') + + def photo_img_thumbnail(self): + im = ImageManager() + if self.photo: + return Markup('') + else: + return Markup('') -Later reference this method like it's a column on your view. + +Create two additional methods in this case *photo_img* and *photo_img_thumbnail*, to inject your own custom HTML, +to show your saved images. In this example the customized method is showing the images, and linking them with the show view. +Notice how the methods are calling *get_url* and *get_url_thumbnail* from ImageManager, these are returning the +url for the images, each image is saved on the filesystem using the global config **IMG_UPLOAD_FOLDER**. +Each image will have two files with different sizes, images are saved as
_sep_ , and _sep_ _thumb .. note:: The "ImageColumn" type, is an extended type from Flask-AppBuilder. +Later reference this method like it's a column on your view. + +To implement image or file support using GridFS from MongoDB is even easier, take a look at the example: + +https://github.com/dpgaspar/Flask-AppBuilder/tree/master/examples/mongoimages + Define your Views (views.py) ---------------------------- @@ -44,15 +66,15 @@ Define your Views (views.py) list_widget = ListThumbnail - label_columns = {'name':'Name','photo':'Photo','photo_img':'Photo'} - list_columns = ['photo_img', 'name'] + label_columns = {'name':'Name','photo':'Photo','photo_img':'Photo', 'photo_img_thumbnail':'Photo'} + list_columns = ['photo_img_thumbnail', 'name'] show_columns = ['photo_img','name'] -Notice that we are overriding the *list_widget*, the widget that is normally used by ModelView. +We are overriding the *list_widget*, the widget that is normally used by ModelView. This will display a thumbnail list, excellent for displaying images. -We're not using the *image* column but the method *photo_img* we have created. -This method will display the image and link it to the show view. +We're not using the *image* column but the methods *photo_img* and *photo_img_thumbnail* we have created. +These methods will display the images and link them to show view. And that's it! images will be saved on the server. Their file names will result in the concatenation of UUID with their original name. They will be resized for optimization. diff --git a/docs/versions.rst b/docs/versions.rst index 39457e300..3797cbafc 100644 --- a/docs/versions.rst +++ b/docs/versions.rst @@ -23,6 +23,7 @@ Improvements and Bug fixes on 1.3.0 - New, AppBuilder.add_link supports endpoint names on href parameter, internally will try to use url_for(href). - Fix, Zero division catch on aggregate average function. - New, added form validators for field min and max length. +- New, Image size can be configured per column, ImageColumn support size and thumbnail size parameters. - (TODO) - fabmanager create-app para SQLA e MongoDB com diferentes esqueletos. - (TODO) - fabmanager support for factory apps. diff --git a/examples/mongoengine/config.py b/examples/mongoengine/config.py index dabd01cf1..13e32c67b 100644 --- a/examples/mongoengine/config.py +++ b/examples/mongoengine/config.py @@ -12,11 +12,6 @@ {'name': 'Flickr', 'url': 'http://www.flickr.com/ '}, {'name': 'MyOpenID', 'url': 'https://www.myopenid.com'}] -#SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db') -#SQLALCHEMY_DATABASE_URI = 'mysql://root:password@localhost/quickhowto' -#SQLALCHEMY_DATABASE_URI = 'postgresql://scott:tiger@localhost:5432/myapp' -#SQLALCHEMY_ECHO = True - MONGODB_SETTINGS = {'DB': 'testing'} BABEL_DEFAULT_LOCALE = 'en' diff --git a/examples/mongoimages/app/models.py b/examples/mongoimages/app/models.py index 8829b493b..6cc5d3ea6 100644 --- a/examples/mongoimages/app/models.py +++ b/examples/mongoimages/app/models.py @@ -70,15 +70,16 @@ def file_show(self): def image_show(self): if self.image: return Markup('') else: return Markup('') def image_thumb_show(self): + print self.image, self.id if self.image: return Markup('') else: return Markup('') diff --git a/examples/mongoimages/app/views.py b/examples/mongoimages/app/views.py index cb67ee8c3..6c9e12125 100644 --- a/examples/mongoimages/app/views.py +++ b/examples/mongoimages/app/views.py @@ -9,9 +9,19 @@ from app import appbuilder -from .models import ContactGroup, Contact, Tags +from .models import ContactGroup, Contact, Tags, Gender + +def fill_gender(): + try: + g1 = Gender(name='Male') + g1.save() + g2 = Gender(name='Female') + g2.save() + except: + pass + class ContactModelView(ModelView): datamodel = MongoEngineInterface(Contact) label_columns = {'image_thumb_show': 'Photo', 'image_show': 'Photo'} @@ -108,4 +118,5 @@ class ContactTimeChartView(GroupByChartView): appbuilder.add_view(ContactTimeChartView, "Contacts Birth Chart", icon="fa-dashboard", category="Contacts") appbuilder.security_cleanup() +fill_gender() diff --git a/examples/quickimages/app/models.py b/examples/quickimages/app/models.py index 250b0cba6..c713a0dd5 100644 --- a/examples/quickimages/app/models.py +++ b/examples/quickimages/app/models.py @@ -26,7 +26,7 @@ class Person(Model): name = Column(String(150), unique = True, nullable=False) address = Column(String(564)) birthday = Column(Date) - photo = Column(ImageColumn(thumbnail_size=(10,10,True), size=(300, 300, True))) + photo = Column(ImageColumn(thumbnail_size=(30, 30, True), size=(300, 300, True))) personal_phone = Column(String(20)) personal_celphone = Column(String(20)) personal_email = Column(String(64)) @@ -41,15 +41,20 @@ class Person(Model): def photo_img(self): im = ImageManager() if self.photo: - return Markup('') + return Markup('') else: - return Markup('') + return Markup('') - - def photo_img(self): + def photo_img_thumbnail(self): im = ImageManager() if self.photo: - return Markup('') + return Markup('') else: - return Markup('') + return Markup('') diff --git a/examples/quickimages/app/views.py b/examples/quickimages/app/views.py index a8be8fe45..e826f46b6 100644 --- a/examples/quickimages/app/views.py +++ b/examples/quickimages/app/views.py @@ -16,15 +16,10 @@ class PersonModelView(ModelView): add_title = 'Add Contact' edit_title = 'Edit Contact' - list_widget = ListThumbnail - - label_columns = {'name': 'Name', 'photo': 'Photo', 'photo_img': 'Photo', 'address': 'Address', - 'birthday': 'Birthday', 'personal_phone': 'Personal Phone', - 'personal_celphone': 'Personal Celphone', 'personal_email': 'Personal Email', - 'business_function': 'Business Function', - 'business_phone': 'Business Phone', 'business_celphone': 'Business Celphone', - 'business_email': 'Business Email', 'notes': 'Notes', 'person_group': 'Group', 'person_group_id': 'Group'} - list_columns = ['photo_img', 'name', 'personal_celphone', 'business_celphone', 'birthday', 'person_group'] + #list_widget = ListThumbnail + + label_columns = {'person_group_id': 'Group', 'photo_img': 'Photo', 'photo_img_thumbnail': 'Photo'} + list_columns = ['photo_img_thumbnail', 'name', 'personal_celphone', 'business_celphone', 'birthday', 'person_group'] show_fieldsets = [ ('Summary', {'fields': ['photo_img', 'name', 'address', 'person_group']}), diff --git a/flask_appbuilder/console.py b/flask_appbuilder/console.py index ed4eff7cf..c15a006d3 100644 --- a/flask_appbuilder/console.py +++ b/flask_appbuilder/console.py @@ -309,15 +309,22 @@ def babel_compile(target): @cli_app.command("create-app") @click.option('--name', prompt="Your new app name", help="Your application name, directory will have this name") -def create_app(name): +@click.option('-engine', prompt="Your engine type, SQLAlchemy or MongoEngine", type=click.Choice(['SQLAlchemy', 'MongoEngine']), + default='SQLAlchemy', help='Write your engine type') +def create_app(name, engine): """ Create a Skeleton application """ try: - url = urlopen("https://github.com/dpgaspar/Flask-AppBuilder-Skeleton/archive/master.zip") + if engine.lower() =='sqlalchemy': + url = urlopen("https://github.com/dpgaspar/Flask-AppBuilder-Skeleton/archive/master.zip") + dirname = "Flask-AppBuilder-Skeleton-master" + elif engine.lower() =='mongoengine': + url = urlopen("https://github.com/dpgaspar/Flask-AppBuilder-Skeleton-me/archive/master.zip") + dirname = "Flask-AppBuilder-Skeleton-me-master" zipfile = ZipFile(StringIO(url.read())) zipfile.extractall() - os.rename("Flask-AppBuilder-Skeleton-master", name) + os.rename(dirname, name) click.echo(click.style('Downloaded the skeleton app, good coding!', fg='green')) except: click.echo(click.style('Something went wrong', fg='red')) diff --git a/flask_appbuilder/filemanager.py b/flask_appbuilder/filemanager.py index cbb46364a..c603e1031 100644 --- a/flask_appbuilder/filemanager.py +++ b/flask_appbuilder/filemanager.py @@ -130,15 +130,18 @@ def get_url(self, filename): return filename.filename return self.relative_path + filename + def get_url_thumbnail(self, filename): + if isinstance(filename, FileStorage): + return filename.filename + return self.relative_path + thumbgen_filename(filename) + # Deletion def delete_file(self, filename): super(ImageManager, self).delete_file(filename) - self.delete_thumbnail(filename) def delete_thumbnail(self, filename): path = self.get_path(self.thumbnail_fn(filename)) - if op.exists(path): os.remove(path)