Skip to content

Commit

Permalink
add a VALIDATORS_TO class variable to ImageCollection
Browse files Browse the repository at this point in the history
  • Loading branch information
pix666 committed Dec 21, 2023
1 parent 050eeca commit ae30289
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 33 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log

## [0.18.6](https://github.com/dldevinc/paper-streamfield/tree/v0.18.6) - 2023-12-21

### Features

- In `ImageCollection` subclasses, you can set the file validators
with the new `VALIDATORS` attribute.

## [0.18.5](https://github.com/dldevinc/paper-streamfield/tree/v0.18.5) - 2023-12-14

### Bug Fixes
Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,39 @@ page = Page.objects.create(
{% endif %}
```

### `ImageCollection`

Для коллекций изображений существует специальный базовый класс `ImageCollection`,
который не требует для каждого отдельного случая создавать отдельный класс элемента
коллекции. Все необходимые параметры можно указать сразу, через атрибуты класса:

```python
from django.db import models
from django.utils.translation import gettext_lazy as _
from paper_uploads.models import *
from paper_uploads.validators import ImageMaxSizeValidator, ImageMinSizeValidator


class PageGallery(ImageCollection):
UPLOAD_TO = "page/gallery",
VARIATIONS = dict(
gallery=dict(
size=(1600, 900),
)
)
VALIDATORS = [
ImageMinSizeValidator(640, 480),
ImageMaxSizeValidator(4000, 3000)
]


class Page(models.Model):
gallery = CollectionField(
PageGallery,
verbose_name=_("gallery")
)
```

## Management команды

### check_uploads
Expand Down
25 changes: 20 additions & 5 deletions paper_uploads/models/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django.db.models.fields.files import FieldFile
from django.db.models.functions import Coalesce
from django.template import loader
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from polymorphic.base import PolymorphicModelBase
Expand All @@ -42,6 +43,7 @@
)
from .fields import CollectionItem
from .fields.base import DynamicStorageFileField
from .fields.helpers import validators_to_options
from .image import VariationalFileField
from .mixins import BacklinkModelMixin, EditableResourceMixin
from .query import PolymorphicResourceManager, ProxyPolymorphicManager
Expand Down Expand Up @@ -746,30 +748,40 @@ def get_file_folder(self) -> str:
folder = getattr(collection_cls, "UPLOAD_TO", None)
return folder or super().get_file_folder()

@cached_property
def validators(self):
collection_cls = self.get_collection_class()
validators = getattr(collection_cls, "VALIDATORS", ())
return [*self.default_validators, *validators, *self._validators]


class ImageCollection(Collection):
"""
Коллекция, позволяющая хранить только изображения.
Вариации могут быть заданы через атрибут класса VARIATIONS,
а путь для хранения файлов - через атрибут UPLOAD_TO.
Вариации, путь для хранения файлов и валидаторы
указываются в атрибутах класса.
Пример:
class MyCollection(ImageCollection):
UPLOAD_TO = "images/%Y-%m-%d"
VARIATIONS = dict(
gallery=dict(
size=(1600, 900),
)
)
VALIDATORS = [
ImageMinSizeValidator(640, 480),
ImageMaxSizeValidator(4000, 3000)
]
"""
UPLOAD_TO: ClassVar[str]
UPLOAD_TO: ClassVar[str] = None
VALIDATORS: ClassVar[Any] = ()

image = CollectionItem(ConfigurableImageItem)

@classmethod
def get_configuration(cls) -> Dict[str, Any]:
return {
default_configuration = {
"strictImageValidation": True,
"acceptFiles": [
"image/bmp",
Expand All @@ -781,3 +793,6 @@ def get_configuration(cls) -> Dict[str, Any]:
"image/webp",
],
}

extra_configuration = validators_to_options(cls.VALIDATORS)
return dict(default_configuration, **extra_configuration)
35 changes: 8 additions & 27 deletions paper_uploads/models/fields/base.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from typing import Any, Dict

import django
from django.core import checks
from django.core.files import File
from django.db import models
from django.db.models.fields.files import FieldFile, FileDescriptor
from django.db.models.signals import post_delete

from ... import validators
from .helpers import validators_to_options


class ResourceFieldBase(models.OneToOneField):
Expand Down Expand Up @@ -144,29 +142,12 @@ def deconstruct(self):
return name, path, args, kwargs

def formfield(self, **kwargs):
return super().formfield(**{"configuration": self.get_configuration(), **kwargs})

def get_configuration(self) -> Dict[str, Any]:
"""
Превращает Django-валидаторы в словарь конфигурации,
который может использоваться для вывода или проверки
на стороне клиента.
"""
config = {}
for v in self.validators:
if isinstance(v, validators.MimeTypeValidator):
config["acceptFiles"] = v.allowed
elif isinstance(v, validators.ExtensionValidator):
config["allowedExtensions"] = v.allowed
elif isinstance(v, validators.MaxSizeValidator):
config["sizeLimit"] = v.limit_value
elif isinstance(v, validators.ImageMinSizeValidator):
config["minImageWidth"] = v.width_limit
config["minImageHeight"] = v.height_limit
elif isinstance(v, validators.ImageMaxSizeValidator):
config["maxImageWidth"] = v.width_limit
config["maxImageHeight"] = v.height_limit
return config
return super().formfield(
**{
"configuration": validators_to_options(self.validators),
**kwargs
}
)


class DynamicStorageFieldFile(FieldFile):
Expand Down Expand Up @@ -291,7 +272,7 @@ class DynamicStorageFileField(models.FileField):
attr_class = DynamicStorageFieldFile
descriptor_class = DynamicStorageFileDescriptor

def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
def __init__(self, verbose_name=None, name=None, upload_to="", storage=None, **kwargs):
self._primary_key_set_explicitly = "primary_key" in kwargs
kwargs.setdefault("max_length", 255)
super(models.FileField, self).__init__(verbose_name, name, **kwargs)
Expand Down
27 changes: 27 additions & 0 deletions paper_uploads/models/fields/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Any, Dict

from ... import validators


def validators_to_options(field_validators) -> Dict[str, Any]:
"""
Превращает Django-валидаторы в словарь конфигурации,
который может использоваться для вывода или проверки
на стороне клиента.
"""
config = {}
for v in field_validators:
if isinstance(v, validators.MimeTypeValidator):
config["acceptFiles"] = v.allowed
elif isinstance(v, validators.ExtensionValidator):
config["allowedExtensions"] = v.allowed
elif isinstance(v, validators.MaxSizeValidator):
config["sizeLimit"] = v.limit_value
elif isinstance(v, validators.ImageMinSizeValidator):
config["minImageWidth"] = v.width_limit
config["minImageHeight"] = v.height_limit
elif isinstance(v, validators.ImageMaxSizeValidator):
config["maxImageWidth"] = v.width_limit
config["maxImageHeight"] = v.height_limit

return config
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Generated by Django 4.2.8 on 2023-12-21 13:19

from django.db import migrations
import django.db.models.deletion
import django.db.models.manager
import paper_uploads.models.fields.collection


class Migration(migrations.Migration):

dependencies = [
('paper_uploads', '0013_configurableimageitem'),
('validators_collections', '0002_alter_page_id'),
]

operations = [
migrations.CreateModel(
name='Gallery',
fields=[
],
options={
'proxy': True,
'default_permissions': (),
'indexes': [],
'constraints': [],
},
bases=('paper_uploads.imagecollection',),
managers=[
('default_mgr', django.db.models.manager.Manager()),
],
),
migrations.AlterField(
model_name='page',
name='collection',
field=paper_uploads.models.fields.collection.CollectionField(on_delete=django.db.models.deletion.SET_NULL, storage=None, to='validators_collections.mixedcollection', upload_to='', verbose_name='mixed collection'),
),
migrations.AddField(
model_name='page',
name='gallery',
field=paper_uploads.models.fields.collection.CollectionField(on_delete=django.db.models.deletion.SET_NULL, storage=None, to='validators_collections.gallery', upload_to='', verbose_name='gallery'),
),
]
13 changes: 12 additions & 1 deletion tests/examples/collections/validators/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
)


class Gallery(ImageCollection):
VALIDATORS = [
ImageMinSizeValidator(640, 480),
ImageMaxSizeValidator(4000, 3000)
]


class MixedCollection(Collection):
svg = CollectionItem(SVGItem, validators=[
MimeTypeValidator(["image/svg+xml"])
Expand All @@ -24,9 +31,13 @@ class MixedCollection(Collection):


class Page(models.Model):
gallery = CollectionField(
Gallery,
verbose_name=_("gallery")
)
collection = CollectionField(
MixedCollection,
verbose_name=_("collection")
verbose_name=_("mixed collection")
)

class Meta:
Expand Down

0 comments on commit ae30289

Please sign in to comment.