Skip to content

Commit ce9a13a

Browse files
committed
Add thumbnail_size property to ImageField
1 parent 438f95f commit ce9a13a

File tree

13 files changed

+44
-63
lines changed

13 files changed

+44
-63
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

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

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

124124
## Related projects and inspirations
125125

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

docs/index.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Overview
22

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

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

123123
## Related projects and inspirations
124124

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

docs/tutorial/using-files-in-models.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,17 @@ You can use two Column type in your model.
2929

3030
Inherits all attributes and methods from [FileField][sqlalchemy_file.types.FileField], but also validates that the
3131
uploaded file is a valid image.
32-
!!! info
32+
!!! note
3333
Using [ImageField][sqlalchemy_file.types.ImageField] is like
3434
using [FileField][sqlalchemy_file.types.FileField]
35-
with [ImageValidator][sqlalchemy_file.validators.ImageValidator]
35+
with [ImageValidator][sqlalchemy_file.validators.ImageValidator] and
36+
[ThumbnailGenerator][sqlalchemy_file.processors.ThumbnailGenerator]
37+
3638

3739
!!! example
3840
```Python
3941
from sqlalchemy import Column, Integer, String
4042
from sqlalchemy.ext.declarative import declarative_base
41-
4243
from sqlalchemy_file import ImageField
4344

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

5051
id = Column(Integer, autoincrement=True, primary_key=True)
5152
title = Column(String(100), unique=True)
52-
cover = Column(ImageField)
53+
cover = Column(ImageField(thumbnail_size=(128, 128)))
5354
```
5455
## Uploaded Files Information
5556
Whenever a supported object is assigned to a [FileField][sqlalchemy_file.types.FileField] or [ImageField][sqlalchemy_file.types.ImageField]

docs_src/tutorial/using-files-in-models/002_imagefield_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ class Book(Base):
1010

1111
id = Column(Integer, autoincrement=True, primary_key=True)
1212
title = Column(String(100), unique=True)
13-
cover = Column(ImageField)
13+
cover = Column(ImageField(thumbnail_size=(128, 128)))

mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
site_name: SQLAlchemy File
2-
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.
2+
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.
33
site_url: https://jowilf.github.io/sqlalchemy-file
44
repo_name: jowilf/sqlalchemy-file
55
repo_url: https://github.com/jowilf/sqlalchemy-file

poetry.lock

Lines changed: 7 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "sqlalchemy-file"
3-
version = "0.1.2"
3+
version = "0.1.3"
44
description = "SQLAlchemy-file is a SQLAlchemy extension for attaching files to SQLAlchemy model and uploading them to various storage."
55
authors = ["Jocelin Hounon <hounonj@gmail.com>"]
66
license = "MIT"
@@ -38,7 +38,6 @@ fasteners = "^0.17.3"
3838
black = "^22.6.0"
3939
coverage = { extras = ["toml"], version = "^6.4.2" }
4040
flake8 = "^5.0.4"
41-
flake8-bugbear = "^22.7.1"
4241
mypy = "^0.971"
4342
isort = "^5.10.1"
4443
mkdocs-material = "^8.2.7"

sqlalchemy_file/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.1.0"
1+
__version__ = "0.1.3"
22

33
from .file import File as File
44
from .types import FileField as FileField

sqlalchemy_file/helpers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
INMEMORY_FILESIZE = 1024 * 1024
1010
LOCAL_STORAGE_DRIVER_NAME = "Local Storage"
1111

12+
1213
def get_metadata_file_obj(metadata: Dict[str, Any]) -> "SpooledTemporaryFile[bytes]":
1314
f = SpooledTemporaryFile(INMEMORY_FILESIZE)
1415
f.write(json.dumps(metadata).encode())

sqlalchemy_file/storage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from libcloud.storage.base import Container
44
from libcloud.storage.types import ObjectDoesNotExistError
5-
from sqlalchemy_file.helpers import get_metadata_file_obj, LOCAL_STORAGE_DRIVER_NAME
5+
from sqlalchemy_file.helpers import LOCAL_STORAGE_DRIVER_NAME, get_metadata_file_obj
66
from sqlalchemy_file.stored_file import StoredFile
77

88

sqlalchemy_file/stored_file.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from libcloud.storage.base import Object
66
from libcloud.storage.types import ObjectDoesNotExistError
7-
87
from sqlalchemy_file.helpers import LOCAL_STORAGE_DRIVER_NAME
98

109

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

3433
def read(self, n: int = -1) -> bytes:
35-
if self.object.driver == LOCAL_STORAGE_DRIVER_NAME:
34+
if self.object.driver.name == LOCAL_STORAGE_DRIVER_NAME:
3635
return open(self.object.get_cdn_url(), "rb").read(n)
3736
_file = tempfile.NamedTemporaryFile()
3837
self.object.download(_file.name, overwrite_existing=True)

sqlalchemy_file/types.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
from sqlalchemy.orm.attributes import get_history
77
from sqlalchemy_file.file import File
88
from sqlalchemy_file.mutable_list import MutableList
9-
from sqlalchemy_file.processors import Processor
9+
from sqlalchemy_file.processors import Processor, ThumbnailGenerator
1010
from sqlalchemy_file.storage import StorageManager
1111
from sqlalchemy_file.validators import ImageValidator, Validator
1212

1313

14-
class FileField(types.TypeDecorator): # type: ignore
14+
class FileField(types.TypeDecorator):
1515

1616
"""
1717
Provides support for storing attachments to **SQLAlchemy** models.
@@ -107,6 +107,7 @@ def __init__(
107107
self,
108108
*args: Tuple[Any],
109109
upload_storage: Optional[str] = None,
110+
thumbnail_size: Optional[Tuple[int, int]] = None,
110111
image_validator: Optional[ImageValidator] = None,
111112
validators: Optional[List[Validator]] = None,
112113
processors: Optional[List[Processor]] = None,
@@ -119,6 +120,9 @@ def __init__(
119120
upload_storage: storage to use
120121
image_validator: ImageField use default image
121122
validator, Use this property to customize it.
123+
thumbnail_size: If set, a thumbnail will be generated
124+
from original image using [ThumbnailGenerator]
125+
[sqlalchemy_file.processors.ThumbnailGenerator]
122126
validators: List of additional validators to apply
123127
processors: List of validators to apply
124128
upload_type: File class to use, could be
@@ -129,8 +133,11 @@ def __init__(
129133
validators = []
130134
if image_validator is None:
131135
image_validator = ImageValidator()
132-
assert isinstance(image_validator, ImageValidator)
133-
validators.insert(0, image_validator)
136+
if thumbnail_size is not None:
137+
if processors is None:
138+
processors = []
139+
processors.append(ThumbnailGenerator(thumbnail_size))
140+
validators.append(image_validator)
134141
super().__init__(
135142
*args,
136143
upload_storage=upload_storage,

tests/test_processor.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import pytest
55
from sqlalchemy import Column, Integer, String, select
66
from sqlalchemy.orm import Session, declarative_base
7-
from sqlalchemy_file.processors import ThumbnailGenerator
87
from sqlalchemy_file.storage import StorageManager
98
from sqlalchemy_file.types import ImageField
109

@@ -36,7 +35,9 @@ class Book(Base):
3635

3736
id = Column(Integer, autoincrement=True, primary_key=True)
3837
title = Column(String(100), unique=True)
39-
cover = Column(ImageField(processors=[ThumbnailGenerator()]))
38+
cover = Column(
39+
ImageField(thumbnail_size=(128, 128))
40+
) # will add thumbnail generator
4041

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

0 commit comments

Comments
 (0)