A library implementing the 'SemVer' scheme.
—
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.
Store Version objects directly in Django models with automatic conversion between database strings and Version objects.
class VersionField(models.CharField):
def __init__(self, partial: bool = False, coerce: bool = False, **kwargs):
"""
Django model field for storing Version objects.
Args:
partial: Allow partial versions (deprecated)
coerce: Automatically coerce invalid version strings to valid format
**kwargs: Standard CharField arguments (max_length defaults to 200)
Database Storage: Stored as VARCHAR string in SemVer format
Python Value: Returns Version object when accessed
"""Usage Examples:
from django.db import models
from semantic_version.django_fields import VersionField
class Package(models.Model):
name = models.CharField(max_length=100)
version = VersionField()
def __str__(self):
return f"{self.name} {self.version}"
# Usage in views/code
package = Package.objects.create(
name="my-package",
version=Version('1.2.3-alpha.1')
)
# Retrieved value is automatically a Version object
retrieved = Package.objects.get(id=package.id)
print(type(retrieved.version)) # <class 'semantic_version.base.Version'>
print(retrieved.version.major) # 1
print(retrieved.version.next_minor()) # Version('1.3.0')Store specification objects for version requirements with support for different specification syntaxes.
class SpecField(models.CharField):
def __init__(self, syntax: str = 'simple', **kwargs):
"""
Django model field for storing specification objects.
Args:
syntax: Specification syntax ('simple' or 'npm')
**kwargs: Standard CharField arguments
Database Storage: Stored as VARCHAR string in specification format
Python Value: Returns SimpleSpec or NpmSpec object based on syntax
"""Usage Examples:
from semantic_version.django_fields import SpecField
class Dependency(models.Model):
package_name = models.CharField(max_length=100)
version_requirement = SpecField(syntax='simple')
npm_requirement = SpecField(syntax='npm')
# Usage
dep = Dependency.objects.create(
package_name="requests",
version_requirement=SimpleSpec('>=2.0.0,<3.0.0'),
npm_requirement=NpmSpec('^2.0.0')
)
# Retrieved values are specification objects
retrieved = Dependency.objects.get(id=dep.id)
print(type(retrieved.version_requirement)) # <class 'semantic_version.base.SimpleSpec'>
print(Version('2.5.0') in retrieved.version_requirement) # TrueThe underlying base field implementation (not typically used directly).
class SemVerField(models.CharField):
"""
Base class for semantic version fields.
Provides common functionality for version and specification fields.
Not intended for direct use - use VersionField or SpecField instead.
Inherits from CharField with max_length defaulting to 200.
"""
def __init__(self, *args, **kwargs): ...
def from_db_value(self, value, expression, connection, *args): ...
def get_prep_value(self, obj): ...
def get_db_prep_value(self, value, connection, prepared=False): ...
def value_to_string(self, obj): ...
def run_validators(self, value): ...Automatic conversion between database storage and Python objects.
def to_python(self, value) -> Version | SimpleSpec | NpmSpec | None:
"""
Convert database value to appropriate Python object.
Args:
value: Database value (string) or existing object
Returns:
Version or specification object, or None if value is None
"""
def from_db_value(self, value, expression, connection, *args) -> Version | SimpleSpec | NpmSpec | None:
"""
Convert value from database to Python object.
Called when loading data from the database.
"""
def get_prep_value(self, obj) -> str | None:
"""
Convert Python object to database storage format.
Args:
obj: Version or specification object
Returns:
String representation for database storage
"""Support for Django migrations and schema changes.
def deconstruct(self) -> tuple:
"""
Return field definition for Django migrations.
Returns:
Tuple of (name, path, args, kwargs) for migration files
"""Automatically fix common version format issues:
class FlexiblePackage(models.Model):
name = models.CharField(max_length=100)
version = VersionField(coerce=True) # Automatically coerce invalid formats
# This will work even with non-standard version strings
package = FlexiblePackage.objects.create(
name="legacy-package",
version="1.2" # Will be coerced to Version('1.2.0')
)
print(package.version) # Version('1.2.0')Support different specification formats in the same model:
class ProjectDependency(models.Model):
name = models.CharField(max_length=100)
simple_spec = SpecField(syntax='simple')
npm_spec = SpecField(syntax='npm')
def check_version(self, version):
"""Check if version satisfies both specifications."""
return (version in self.simple_spec and
version in self.npm_spec)
dep = ProjectDependency.objects.create(
name="lodash",
simple_spec=SimpleSpec('>=4.0.0,<5.0.0'),
npm_spec=NpmSpec('^4.0.0')
)
test_version = Version('4.17.21')
print(dep.check_version(test_version)) # TrueUse version fields in database queries:
# Filter by exact version
packages = Package.objects.filter(version='1.2.3')
# Use string representations in queries
recent_packages = Package.objects.filter(version__gte='2.0.0')
# Complex queries with version comparisons
major_v1 = Package.objects.filter(version__startswith='1.')
# Order by version (uses string ordering, may not be semantically correct)
ordered = Package.objects.order_by('version')Extend field behavior for specific use cases:
class StrictVersionField(VersionField):
"""Version field that only accepts release versions (no prerelease)."""
def to_python(self, value):
version = super().to_python(value)
if version and version.prerelease:
raise ValidationError('Prerelease versions not allowed')
return version
class Package(models.Model):
name = models.CharField(max_length=100)
stable_version = StrictVersionField()# Generated migration
from django.db import migrations
from semantic_version.django_fields import VersionField, SpecField
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='package',
name='version',
field=VersionField(),
),
migrations.AddField(
model_name='dependency',
name='requirement',
field=SpecField(syntax='simple'),
),
]# Migration to add coercion to existing field
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_add_version_fields'),
]
operations = [
migrations.AlterField(
model_name='package',
name='version',
field=VersionField(coerce=True),
),
]Django integration provides comprehensive error handling:
from django.core.exceptions import ValidationError
# Invalid version strings raise ValidationError
try:
package = Package(name="test", version="invalid.version")
package.full_clean() # Triggers validation
except ValidationError as e:
print(f"Validation error: {e}")
# Handle coercion failures
class SafePackage(models.Model):
name = models.CharField(max_length=100)
version = VersionField(coerce=True, blank=True, null=True)
def clean(self):
if self.version:
try:
# Ensure version can be coerced
Version.coerce(str(self.version))
except ValueError:
raise ValidationError({'version': 'Invalid version format'})select_related() and prefetch_related() as with any CharFieldblank=True, null=True for optional versionsInstall with Tessl CLI
npx tessl i tessl/pypi-semantic-version