Skip to content

Commit

Permalink
Add thumbnail_size property to ImageField
Browse files Browse the repository at this point in the history
  • Loading branch information
jowilf committed Aug 23, 2022
1 parent 438f95f commit ce9a13a
Show file tree
Hide file tree
Showing 13 changed files with 44 additions and 63 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


**SQLAlchemy-file** is a [SQLAlchemy](https://www.sqlalchemy.org/) extension for attaching files to SQLAlchemy model and
uploading them to various storage such as Amazon S3, Rackspace CloudFiles, Google Storage and others
uploading them to various storage such as Local Storage, Amazon S3, Rackspace CloudFiles, Google Storage and others
using [Apache Libcloud](https://github.com/apache/libcloud).

<p align="center">
Expand Down Expand Up @@ -123,7 +123,9 @@ with Session(engine) as session:

## Related projects and inspirations

* [Depot: ](https://github.com/amol-/depot) When I was looking for a library like this, depot was the
best I saw. But it offers less storage backend, doesn't support multiple files and doesn't work with
[SQLModel](https://github.com/tiangolo/sqlmodel). This project inspired **SQLAlchemy-file** extensively
* [filedepot: ](https://github.com/amol-/depot) When I was looking for a library like this, depot was the
best I saw. This project inspired **SQLAlchemy-file** extensively
and some features are implemented the same.
* [sqlalchemy-media](https://github.com/pylover/sqlalchemy-media) Another attachment extension for SqlAlchemy
to manage assets which are associated with database models

9 changes: 5 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Overview

**SQLAlchemy-file** is a [SQLAlchemy](https://www.sqlalchemy.org/) extension for attaching files to SQLAlchemy model and
uploading them to various storage such as Amazon S3, Rackspace CloudFiles, Google Storage and others
uploading them to various storage such as Local Storage, Amazon S3, Rackspace CloudFiles, Google Storage and others
using [Apache Libcloud](https://github.com/apache/libcloud).

<p align="center">
Expand Down Expand Up @@ -122,7 +122,8 @@ with Session(engine) as session:

## Related projects and inspirations

* [Depot: ](https://github.com/amol-/depot) When I was looking for a library like this, depot was the
best I saw. But it offers less storage backend, doesn't support multiple files and doesn't work with
[SQLModel](https://github.com/tiangolo/sqlmodel). This project inspired **SQLAlchemy-file** extensively
* [filedepot: ](https://github.com/amol-/depot) When I was looking for a library like this, depot was the
best I saw. This project inspired **SQLAlchemy-file** extensively
and some features are implemented the same.
* [sqlalchemy-media](https://github.com/pylover/sqlalchemy-media) Another attachment extension for SqlAlchemy
to manage assets which are associated with database models
9 changes: 5 additions & 4 deletions docs/tutorial/using-files-in-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@ You can use two Column type in your model.

Inherits all attributes and methods from [FileField][sqlalchemy_file.types.FileField], but also validates that the
uploaded file is a valid image.
!!! info
!!! note
Using [ImageField][sqlalchemy_file.types.ImageField] is like
using [FileField][sqlalchemy_file.types.FileField]
with [ImageValidator][sqlalchemy_file.validators.ImageValidator]
with [ImageValidator][sqlalchemy_file.validators.ImageValidator] and
[ThumbnailGenerator][sqlalchemy_file.processors.ThumbnailGenerator]


!!! example
```Python
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy_file import ImageField

Base = declarative_base()
Expand All @@ -49,7 +50,7 @@ uploaded file is a valid image.

id = Column(Integer, autoincrement=True, primary_key=True)
title = Column(String(100), unique=True)
cover = Column(ImageField)
cover = Column(ImageField(thumbnail_size=(128, 128)))
```
## Uploaded Files Information
Whenever a supported object is assigned to a [FileField][sqlalchemy_file.types.FileField] or [ImageField][sqlalchemy_file.types.ImageField]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ class Book(Base):

id = Column(Integer, autoincrement=True, primary_key=True)
title = Column(String(100), unique=True)
cover = Column(ImageField)
cover = Column(ImageField(thumbnail_size=(128, 128)))
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
site_name: SQLAlchemy File
site_description: SQLAlchemy-file is a SQLAlchemy extension for attaching files to SQLAlchemy model and uploading them to various storage such as Amazon S3, Rackspace CloudFiles, Google Storage and others using Apache Libcloud.
site_description: SQLAlchemy-file is a SQLAlchemy extension for attaching files to SQLAlchemy model and uploading them to various storage such as Local Storage Amazon S3, Rackspace CloudFiles, Google Storage and others using Apache Libcloud.
site_url: https://jowilf.github.io/sqlalchemy-file
repo_name: jowilf/sqlalchemy-file
repo_url: https://github.com/jowilf/sqlalchemy-file
Expand Down
44 changes: 7 additions & 37 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "sqlalchemy-file"
version = "0.1.2"
version = "0.1.3"
description = "SQLAlchemy-file is a SQLAlchemy extension for attaching files to SQLAlchemy model and uploading them to various storage."
authors = ["Jocelin Hounon <[email protected]>"]
license = "MIT"
Expand Down Expand Up @@ -38,7 +38,6 @@ fasteners = "^0.17.3"
black = "^22.6.0"
coverage = { extras = ["toml"], version = "^6.4.2" }
flake8 = "^5.0.4"
flake8-bugbear = "^22.7.1"
mypy = "^0.971"
isort = "^5.10.1"
mkdocs-material = "^8.2.7"
Expand Down
2 changes: 1 addition & 1 deletion sqlalchemy_file/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.1.0"
__version__ = "0.1.3"

from .file import File as File
from .types import FileField as FileField
Expand Down
1 change: 1 addition & 0 deletions sqlalchemy_file/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
INMEMORY_FILESIZE = 1024 * 1024
LOCAL_STORAGE_DRIVER_NAME = "Local Storage"


def get_metadata_file_obj(metadata: Dict[str, Any]) -> "SpooledTemporaryFile[bytes]":
f = SpooledTemporaryFile(INMEMORY_FILESIZE)
f.write(json.dumps(metadata).encode())
Expand Down
2 changes: 1 addition & 1 deletion sqlalchemy_file/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from libcloud.storage.base import Container
from libcloud.storage.types import ObjectDoesNotExistError
from sqlalchemy_file.helpers import get_metadata_file_obj, LOCAL_STORAGE_DRIVER_NAME
from sqlalchemy_file.helpers import LOCAL_STORAGE_DRIVER_NAME, get_metadata_file_obj
from sqlalchemy_file.stored_file import StoredFile


Expand Down
3 changes: 1 addition & 2 deletions sqlalchemy_file/stored_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from libcloud.storage.base import Object
from libcloud.storage.types import ObjectDoesNotExistError

from sqlalchemy_file.helpers import LOCAL_STORAGE_DRIVER_NAME


Expand Down Expand Up @@ -32,7 +31,7 @@ def get_cdn_url(self) -> Optional[str]:
return None

def read(self, n: int = -1) -> bytes:
if self.object.driver == LOCAL_STORAGE_DRIVER_NAME:
if self.object.driver.name == LOCAL_STORAGE_DRIVER_NAME:
return open(self.object.get_cdn_url(), "rb").read(n)
_file = tempfile.NamedTemporaryFile()
self.object.download(_file.name, overwrite_existing=True)
Expand Down
15 changes: 11 additions & 4 deletions sqlalchemy_file/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
from sqlalchemy.orm.attributes import get_history
from sqlalchemy_file.file import File
from sqlalchemy_file.mutable_list import MutableList
from sqlalchemy_file.processors import Processor
from sqlalchemy_file.processors import Processor, ThumbnailGenerator
from sqlalchemy_file.storage import StorageManager
from sqlalchemy_file.validators import ImageValidator, Validator


class FileField(types.TypeDecorator): # type: ignore
class FileField(types.TypeDecorator):

"""
Provides support for storing attachments to **SQLAlchemy** models.
Expand Down Expand Up @@ -107,6 +107,7 @@ def __init__(
self,
*args: Tuple[Any],
upload_storage: Optional[str] = None,
thumbnail_size: Optional[Tuple[int, int]] = None,
image_validator: Optional[ImageValidator] = None,
validators: Optional[List[Validator]] = None,
processors: Optional[List[Processor]] = None,
Expand All @@ -119,6 +120,9 @@ def __init__(
upload_storage: storage to use
image_validator: ImageField use default image
validator, Use this property to customize it.
thumbnail_size: If set, a thumbnail will be generated
from original image using [ThumbnailGenerator]
[sqlalchemy_file.processors.ThumbnailGenerator]
validators: List of additional validators to apply
processors: List of validators to apply
upload_type: File class to use, could be
Expand All @@ -129,8 +133,11 @@ def __init__(
validators = []
if image_validator is None:
image_validator = ImageValidator()
assert isinstance(image_validator, ImageValidator)
validators.insert(0, image_validator)
if thumbnail_size is not None:
if processors is None:
processors = []
processors.append(ThumbnailGenerator(thumbnail_size))
validators.append(image_validator)
super().__init__(
*args,
upload_storage=upload_storage,
Expand Down
5 changes: 3 additions & 2 deletions tests/test_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import pytest
from sqlalchemy import Column, Integer, String, select
from sqlalchemy.orm import Session, declarative_base
from sqlalchemy_file.processors import ThumbnailGenerator
from sqlalchemy_file.storage import StorageManager
from sqlalchemy_file.types import ImageField

Expand Down Expand Up @@ -36,7 +35,9 @@ class Book(Base):

id = Column(Integer, autoincrement=True, primary_key=True)
title = Column(String(100), unique=True)
cover = Column(ImageField(processors=[ThumbnailGenerator()]))
cover = Column(
ImageField(thumbnail_size=(128, 128))
) # will add thumbnail generator

def __repr__(self):
return "<Book: id %s ; name: %s; cover %s;>" % (
Expand Down

0 comments on commit ce9a13a

Please sign in to comment.