class AssetFormSet(BaseGenericInlineFormSet): model = models.get_asset_model() def __init__(self, data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs): if not kwargs.get('initial') and not (data or files): kwargs['initial'] = self.construct_initial(instance) super().__init__(data, files, instance, save_as_new, prefix, queryset, **kwargs) @staticmethod def construct_initial(instance): asset_type_model = models.get_asset_type_model() initial = [] for asset_type in asset_type_model.objects.get_required(instance): initial.append({'asset_type': asset_type.pk}) return initial def add_fields(self, form, index): super().add_fields(form, index) qs = models.get_asset_type_model().objects.get_for_model(self.instance) form.fields['asset_type'].queryset = qs def clean(self): super().clean() if not self.is_valid(): return duplicated_asset_types = set() added_asset_types = set() qs = models.get_asset_type_model().objects.get_required(self.instance) required_asset_types = set(qs.values_list('pk', flat=True)) for asset_data in self.cleaned_data: active = asset_data.get('active') if not active: # We only perform extra validation for active assets continue asset_type = asset_data.get('asset_type') if not asset_type: # empty field value continue if asset_type.pk in added_asset_types: # there are more than one active assets of this type duplicated_asset_types.add(asset_type.pk) # track whether there are active assets for all required types added_asset_types.add(asset_type.pk) errors = [] missing = required_asset_types - added_asset_types if missing: qs = models.get_asset_type_model().objects.filter( pk__in=missing).values_list('slug', flat=True) msg = _("Missing required asset types: %s") errors.append(ValidationError(msg % ', '.join(qs))) if duplicated_asset_types: qs = models.get_asset_type_model().objects.filter( pk__in=duplicated_asset_types).values_list('slug', flat=True) msg = _("Duplicate active assets for types: %s") errors.append(ValidationError(msg % ', '.join(qs))) if errors: raise ValidationError(errors)
class AssetsInline(GenericTabularInline): model = models.get_asset_model() formset = forms.AssetFormSet
from typing import Type from django.db.models.signals import pre_delete from django.dispatch import receiver from image_assets import models # noinspection PyUnusedLocal @receiver(pre_delete, sender=models.get_asset_model()) def move_asset_file_to_deleted_asset( sender, *, instance: models.Asset, **kwargs): """ When asset is deleted, it's file is moved to deleted asset instance.""" models.get_deleted_asset_model().objects.create( image=instance.image, content_type_id=instance.content_type_id, object_id=instance.object_id, asset_type_id=instance.asset_type_id) # noinspection PyUnusedLocal @receiver(pre_delete, sender=models.get_deleted_asset_model()) def delete_asset_file_for_deleted_asset( sender, *, instance: models.DeletedAsset, **kwargs): """ When deleted asset is deleted from db, it's file is purged from storage. """ instance.image.delete(save=False)
import io from typing import Tuple, Optional, Iterable from PIL import Image from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile from django.db.models.base import ModelBase, Model from image_assets import models AssetType = models.get_asset_type_model() Asset = models.get_asset_model() try: from image_assets.tests.factories import * except ImportError: # pragma: no cover # factory-boy not installed, no default fuzzy attributes will be available AssetTypeFactory = AssetType.objects AssetFactory = Asset.objects __all__ = ["ImageAssetsMixin"] class ImageAssetsMixin: @classmethod def create_image(cls, dimensions: Tuple[int, int] = (60, 30), color: str = "red") -> Image.Image: """ Creates valid image.""" return Image.new('RGB', dimensions, color=color)
def test_str(self): """ Check __str__ method.""" self.assertIsInstance(self.asset.__str__(), str) empty = assets_models.get_asset_model()() self.assertIsInstance(empty.__str__(), str)