0
# Django Integration
1
2
Django model fields for storing Version and specification objects in databases with automatic serialization/deserialization, validation, and migration support. Seamlessly integrate semantic versioning into Django applications.
3
4
## Capabilities
5
6
### Version Field
7
8
Store Version objects directly in Django models with automatic conversion between database strings and Version objects.
9
10
```python { .api }
11
class VersionField(models.CharField):
12
def __init__(self, partial: bool = False, coerce: bool = False, **kwargs):
13
"""
14
Django model field for storing Version objects.
15
16
Args:
17
partial: Allow partial versions (deprecated)
18
coerce: Automatically coerce invalid version strings to valid format
19
**kwargs: Standard CharField arguments (max_length defaults to 200)
20
21
Database Storage: Stored as VARCHAR string in SemVer format
22
Python Value: Returns Version object when accessed
23
"""
24
```
25
26
**Usage Examples:**
27
28
```python
29
from django.db import models
30
from semantic_version.django_fields import VersionField
31
32
class Package(models.Model):
33
name = models.CharField(max_length=100)
34
version = VersionField()
35
36
def __str__(self):
37
return f"{self.name} {self.version}"
38
39
# Usage in views/code
40
package = Package.objects.create(
41
name="my-package",
42
version=Version('1.2.3-alpha.1')
43
)
44
45
# Retrieved value is automatically a Version object
46
retrieved = Package.objects.get(id=package.id)
47
print(type(retrieved.version)) # <class 'semantic_version.base.Version'>
48
print(retrieved.version.major) # 1
49
print(retrieved.version.next_minor()) # Version('1.3.0')
50
```
51
52
### Specification Field
53
54
Store specification objects for version requirements with support for different specification syntaxes.
55
56
```python { .api }
57
class SpecField(models.CharField):
58
def __init__(self, syntax: str = 'simple', **kwargs):
59
"""
60
Django model field for storing specification objects.
61
62
Args:
63
syntax: Specification syntax ('simple' or 'npm')
64
**kwargs: Standard CharField arguments
65
66
Database Storage: Stored as VARCHAR string in specification format
67
Python Value: Returns SimpleSpec or NpmSpec object based on syntax
68
"""
69
```
70
71
**Usage Examples:**
72
73
```python
74
from semantic_version.django_fields import SpecField
75
76
class Dependency(models.Model):
77
package_name = models.CharField(max_length=100)
78
version_requirement = SpecField(syntax='simple')
79
npm_requirement = SpecField(syntax='npm')
80
81
# Usage
82
dep = Dependency.objects.create(
83
package_name="requests",
84
version_requirement=SimpleSpec('>=2.0.0,<3.0.0'),
85
npm_requirement=NpmSpec('^2.0.0')
86
)
87
88
# Retrieved values are specification objects
89
retrieved = Dependency.objects.get(id=dep.id)
90
print(type(retrieved.version_requirement)) # <class 'semantic_version.base.SimpleSpec'>
91
print(Version('2.5.0') in retrieved.version_requirement) # True
92
```
93
94
### Base Field Class
95
96
The underlying base field implementation (not typically used directly).
97
98
```python { .api }
99
class SemVerField(models.CharField):
100
"""
101
Base class for semantic version fields.
102
103
Provides common functionality for version and specification fields.
104
Not intended for direct use - use VersionField or SpecField instead.
105
106
Inherits from CharField with max_length defaulting to 200.
107
"""
108
109
def __init__(self, *args, **kwargs): ...
110
def from_db_value(self, value, expression, connection, *args): ...
111
def get_prep_value(self, obj): ...
112
def get_db_prep_value(self, value, connection, prepared=False): ...
113
def value_to_string(self, obj): ...
114
def run_validators(self, value): ...
115
```
116
117
## Field Methods
118
119
### Database Conversion
120
121
Automatic conversion between database storage and Python objects.
122
123
```python { .api }
124
def to_python(self, value) -> Version | SimpleSpec | NpmSpec | None:
125
"""
126
Convert database value to appropriate Python object.
127
128
Args:
129
value: Database value (string) or existing object
130
131
Returns:
132
Version or specification object, or None if value is None
133
"""
134
135
def from_db_value(self, value, expression, connection, *args) -> Version | SimpleSpec | NpmSpec | None:
136
"""
137
Convert value from database to Python object.
138
139
Called when loading data from the database.
140
"""
141
142
def get_prep_value(self, obj) -> str | None:
143
"""
144
Convert Python object to database storage format.
145
146
Args:
147
obj: Version or specification object
148
149
Returns:
150
String representation for database storage
151
"""
152
```
153
154
### Migration Support
155
156
Support for Django migrations and schema changes.
157
158
```python { .api }
159
def deconstruct(self) -> tuple:
160
"""
161
Return field definition for Django migrations.
162
163
Returns:
164
Tuple of (name, path, args, kwargs) for migration files
165
"""
166
```
167
168
## Advanced Usage
169
170
### Version Field with Coercion
171
172
Automatically fix common version format issues:
173
174
```python
175
class FlexiblePackage(models.Model):
176
name = models.CharField(max_length=100)
177
version = VersionField(coerce=True) # Automatically coerce invalid formats
178
179
# This will work even with non-standard version strings
180
package = FlexiblePackage.objects.create(
181
name="legacy-package",
182
version="1.2" # Will be coerced to Version('1.2.0')
183
)
184
185
print(package.version) # Version('1.2.0')
186
```
187
188
### Multiple Specification Syntaxes
189
190
Support different specification formats in the same model:
191
192
```python
193
class ProjectDependency(models.Model):
194
name = models.CharField(max_length=100)
195
simple_spec = SpecField(syntax='simple')
196
npm_spec = SpecField(syntax='npm')
197
198
def check_version(self, version):
199
"""Check if version satisfies both specifications."""
200
return (version in self.simple_spec and
201
version in self.npm_spec)
202
203
dep = ProjectDependency.objects.create(
204
name="lodash",
205
simple_spec=SimpleSpec('>=4.0.0,<5.0.0'),
206
npm_spec=NpmSpec('^4.0.0')
207
)
208
209
test_version = Version('4.17.21')
210
print(dep.check_version(test_version)) # True
211
```
212
213
### Query Operations
214
215
Use version fields in database queries:
216
217
```python
218
# Filter by exact version
219
packages = Package.objects.filter(version='1.2.3')
220
221
# Use string representations in queries
222
recent_packages = Package.objects.filter(version__gte='2.0.0')
223
224
# Complex queries with version comparisons
225
major_v1 = Package.objects.filter(version__startswith='1.')
226
227
# Order by version (uses string ordering, may not be semantically correct)
228
ordered = Package.objects.order_by('version')
229
```
230
231
### Custom Field Behavior
232
233
Extend field behavior for specific use cases:
234
235
```python
236
class StrictVersionField(VersionField):
237
"""Version field that only accepts release versions (no prerelease)."""
238
239
def to_python(self, value):
240
version = super().to_python(value)
241
if version and version.prerelease:
242
raise ValidationError('Prerelease versions not allowed')
243
return version
244
245
class Package(models.Model):
246
name = models.CharField(max_length=100)
247
stable_version = StrictVersionField()
248
```
249
250
## Migration Examples
251
252
### Adding Version Fields
253
254
```python
255
# Generated migration
256
from django.db import migrations
257
from semantic_version.django_fields import VersionField, SpecField
258
259
class Migration(migrations.Migration):
260
dependencies = [
261
('myapp', '0001_initial'),
262
]
263
264
operations = [
265
migrations.AddField(
266
model_name='package',
267
name='version',
268
field=VersionField(),
269
),
270
migrations.AddField(
271
model_name='dependency',
272
name='requirement',
273
field=SpecField(syntax='simple'),
274
),
275
]
276
```
277
278
### Changing Field Options
279
280
```python
281
# Migration to add coercion to existing field
282
class Migration(migrations.Migration):
283
dependencies = [
284
('myapp', '0002_add_version_fields'),
285
]
286
287
operations = [
288
migrations.AlterField(
289
model_name='package',
290
name='version',
291
field=VersionField(coerce=True),
292
),
293
]
294
```
295
296
## Error Handling
297
298
Django integration provides comprehensive error handling:
299
300
```python
301
from django.core.exceptions import ValidationError
302
303
# Invalid version strings raise ValidationError
304
try:
305
package = Package(name="test", version="invalid.version")
306
package.full_clean() # Triggers validation
307
except ValidationError as e:
308
print(f"Validation error: {e}")
309
310
# Handle coercion failures
311
class SafePackage(models.Model):
312
name = models.CharField(max_length=100)
313
version = VersionField(coerce=True, blank=True, null=True)
314
315
def clean(self):
316
if self.version:
317
try:
318
# Ensure version can be coerced
319
Version.coerce(str(self.version))
320
except ValueError:
321
raise ValidationError({'version': 'Invalid version format'})
322
```
323
324
## Performance Considerations
325
326
- Version fields store strings in database - queries use string comparison
327
- For semantic version ordering, load objects and sort in Python
328
- Consider indexing version fields for frequently queried ranges
329
- Use `select_related()` and `prefetch_related()` as with any CharField
330
- Coercion happens on every field access - cache results if needed
331
332
## Best Practices
333
334
1. **Use coercion sparingly** - only when dealing with legacy data
335
2. **Validate at model level** - add custom clean() methods for complex validation
336
3. **Choose appropriate syntax** - use 'simple' for most cases, 'npm' for Node.js compatibility
337
4. **Index frequently queried fields** - especially version fields used in filtering
338
5. **Handle None values** - use `blank=True, null=True` for optional versions
339
6. **Document field behavior** - specify which syntax and options are used