CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-semantic-version

A library implementing the 'SemVer' scheme.

Pending
Overview
Eval results
Files

django-integration.mddocs/

Django Integration

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.

Capabilities

Version Field

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')

Specification Field

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)  # True

Base Field Class

The 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): ...

Field Methods

Database Conversion

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
    """

Migration Support

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
    """

Advanced Usage

Version Field with Coercion

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')

Multiple Specification Syntaxes

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))  # True

Query Operations

Use 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')

Custom Field Behavior

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()

Migration Examples

Adding Version Fields

# 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'),
        ),
    ]

Changing Field Options

# 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),
        ),
    ]

Error Handling

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'})

Performance Considerations

  • Version fields store strings in database - queries use string comparison
  • For semantic version ordering, load objects and sort in Python
  • Consider indexing version fields for frequently queried ranges
  • Use select_related() and prefetch_related() as with any CharField
  • Coercion happens on every field access - cache results if needed

Best Practices

  1. Use coercion sparingly - only when dealing with legacy data
  2. Validate at model level - add custom clean() methods for complex validation
  3. Choose appropriate syntax - use 'simple' for most cases, 'npm' for Node.js compatibility
  4. Index frequently queried fields - especially version fields used in filtering
  5. Handle None values - use blank=True, null=True for optional versions
  6. Document field behavior - specify which syntax and options are used

Install with Tessl CLI

npx tessl i tessl/pypi-semantic-version

docs

django-integration.md

index.md

specification-matching.md

version-operations.md

tile.json