12
12
class ImageBackend :
13
13
"""
14
14
Base class for image backends.
15
-
15
+
16
16
Backends handle image storage, processing, and URL generation
17
17
for different image management systems.
18
18
"""
19
-
19
+
20
20
def save_image (self , image_file , instance , field_name , ** options ):
21
21
"""
22
22
Save an uploaded image file.
23
-
23
+
24
24
Args:
25
25
image_file: The uploaded image file object
26
26
instance: The model instance containing the field
27
27
field_name: Name of the field in the model
28
28
**options: Additional backend-specific options
29
-
29
+
30
30
Returns:
31
31
Reference to the saved image (backend-specific format)
32
32
"""
33
33
raise NotImplementedError ("Subclasses must implement save_image()" )
34
-
34
+
35
35
def get_image_url (self , image_reference , size_options = None , ** kwargs ):
36
36
"""
37
37
Get the URL for an image with optional sizing.
38
-
38
+
39
39
Args:
40
40
image_reference: Backend-specific image reference
41
41
size_options: Dict with size/crop options
42
42
**kwargs: Additional options
43
-
43
+
44
44
Returns:
45
45
String URL to the image
46
46
"""
47
47
raise NotImplementedError ("Subclasses must implement get_image_url()" )
48
-
48
+
49
49
def get_srcset_data (self , image_reference , breakpoints , ** kwargs ):
50
50
"""
51
51
Generate responsive image srcset data.
52
-
52
+
53
53
Args:
54
54
image_reference: Backend-specific image reference
55
55
breakpoints: List of viewport breakpoints
56
56
**kwargs: Additional options
57
-
57
+
58
58
Returns:
59
59
List of tuples: [(width, url), ...]
60
60
"""
61
61
raise NotImplementedError ("Subclasses must implement get_srcset_data()" )
62
-
62
+
63
63
def delete_image (self , image_reference ):
64
64
"""
65
65
Delete an image and its variants.
66
-
66
+
67
67
Args:
68
68
image_reference: Backend-specific image reference
69
69
"""
70
70
raise NotImplementedError ("Subclasses must implement delete_image()" )
71
-
71
+
72
72
def get_image_info (self , image_reference ):
73
73
"""
74
74
Get metadata about an image.
75
-
75
+
76
76
Args:
77
77
image_reference: Backend-specific image reference
78
-
78
+
79
79
Returns:
80
80
Dict with keys: width, height, format, size, alt_text, etc.
81
81
"""
82
82
raise NotImplementedError ("Subclasses must implement get_image_info()" )
83
-
83
+
84
84
def validate_image (self , image_file , ** options ):
85
85
"""
86
86
Validate an image file before saving.
87
-
87
+
88
88
Args:
89
89
image_file: The image file to validate
90
90
**options: Validation options
91
-
91
+
92
92
Raises:
93
93
ValidationError: If image is invalid
94
94
"""
@@ -97,23 +97,23 @@ def validate_image(self, image_file, **options):
97
97
98
98
class BackendRegistry :
99
99
"""Registry for managing available image backends."""
100
-
100
+
101
101
def __init__ (self ):
102
102
self ._backends = {}
103
103
self ._loaded = False
104
-
104
+
105
105
def _load_backends (self ):
106
106
"""Load backends from Django settings."""
107
107
if self ._loaded :
108
108
return
109
-
109
+
110
110
backend_settings = getattr (settings , 'DJANGOCMS_PICTURE_BACKENDS' , {})
111
-
111
+
112
112
# If no backends are configured, register default ones
113
113
if not backend_settings :
114
114
_register_default_backends ()
115
115
return
116
-
116
+
117
117
for name , backend_path in backend_settings .items ():
118
118
try :
119
119
backend_class = import_string (backend_path )
@@ -123,32 +123,32 @@ def _load_backends(self):
123
123
# This allows the system to work even if some backends are not available
124
124
import logging
125
125
logging .warning (f"Could not import backend '{ name } ' from '{ backend_path } ': { e } " )
126
-
126
+
127
127
self ._loaded = True
128
-
128
+
129
129
def get_backend (self , name = None ):
130
130
"""
131
131
Get a backend instance by name.
132
-
132
+
133
133
Args:
134
134
name: Backend name, defaults to DJANGOCMS_PICTURE_DEFAULT_BACKEND
135
-
135
+
136
136
Returns:
137
137
Backend instance
138
138
"""
139
139
self ._load_backends ()
140
-
140
+
141
141
if name is None :
142
142
name = getattr (settings , 'DJANGOCMS_PICTURE_DEFAULT_BACKEND' , 'filer' )
143
-
143
+
144
144
if name not in self ._backends :
145
145
available = ', ' .join (self ._backends .keys ())
146
146
raise ImproperlyConfigured (
147
147
f"Backend '{ name } ' not found. Available backends: { available } "
148
148
)
149
-
149
+
150
150
return self ._backends [name ]()
151
-
151
+
152
152
def get_available_backends (self ):
153
153
"""Get list of available backend names."""
154
154
self ._load_backends ()
@@ -167,10 +167,10 @@ def _register_default_backends():
167
167
backend_registry ._backends ['filer' ] = FilerImageBackend
168
168
except ImportError :
169
169
pass # Filer not available
170
-
170
+
171
171
# Mark as loaded so it doesn't try to load from settings
172
172
backend_registry ._loaded = True
173
173
174
174
175
175
# Don't auto-register default backends on import to avoid Django setup issues
176
- # They will be registered when first accessed through _load_backends()
176
+ # They will be registered when first accessed through _load_backends()
0 commit comments