11279 add collation

This commit is contained in:
Arthur Hanson 2024-11-13 09:01:47 -08:00
parent 33099499d6
commit fb19be9cca
11 changed files with 366 additions and 90 deletions

View File

@ -1,19 +0,0 @@
# Generated by Django 5.0.9 on 2024-11-12 22:21
from django.contrib.postgres.operations import CreateCollation
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('dcim', '0196_qinq_svlan'),
]
operations = [
CreateCollation(
"natural_sort",
provider="icu",
locale="und-u-ks-level2-kn-true",
),
]

View File

@ -0,0 +1,306 @@
# Generated by Django 5.0.9 on 2024-11-12 22:21
from django.contrib.postgres.operations import CreateCollation
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0196_qinq_svlan'),
]
operations = [
CreateCollation(
"natural_sort",
provider="icu",
locale="und-u-kn-true",
),
migrations.AlterModelOptions(
name='site',
options={'ordering': ('name',)},
),
migrations.AlterField(
model_name='site',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=100, unique=True),
),
migrations.AlterModelOptions(
name='consoleport',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='consoleporttemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.AlterModelOptions(
name='consoleserverport',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='consoleserverporttemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.AlterModelOptions(
name='device',
options={'ordering': ('name', 'pk')},
),
migrations.AlterModelOptions(
name='devicebay',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='devicebaytemplate',
options={'ordering': ('device_type', 'name')},
),
migrations.AlterModelOptions(
name='frontport',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='frontporttemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.AlterModelOptions(
name='interfacetemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.AlterModelOptions(
name='inventoryitem',
options={'ordering': ('device__id', 'parent__id', 'name')},
),
migrations.AlterModelOptions(
name='inventoryitemtemplate',
options={'ordering': ('device_type__id', 'parent__id', 'name')},
),
migrations.AlterModelOptions(
name='modulebay',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='modulebaytemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.AlterModelOptions(
name='poweroutlet',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='poweroutlettemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.AlterModelOptions(
name='powerport',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='powerporttemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.AlterModelOptions(
name='rack',
options={'ordering': ('site', 'location', 'name', 'pk')},
),
migrations.AlterModelOptions(
name='rearport',
options={'ordering': ('device', 'name')},
),
migrations.AlterModelOptions(
name='rearporttemplate',
options={'ordering': ('device_type', 'module_type', 'name')},
),
migrations.RemoveField(
model_name='consoleport',
name='_name',
),
migrations.RemoveField(
model_name='consoleporttemplate',
name='_name',
),
migrations.RemoveField(
model_name='consoleserverport',
name='_name',
),
migrations.RemoveField(
model_name='consoleserverporttemplate',
name='_name',
),
migrations.RemoveField(
model_name='device',
name='_name',
),
migrations.RemoveField(
model_name='devicebay',
name='_name',
),
migrations.RemoveField(
model_name='devicebaytemplate',
name='_name',
),
migrations.RemoveField(
model_name='frontport',
name='_name',
),
migrations.RemoveField(
model_name='frontporttemplate',
name='_name',
),
migrations.RemoveField(
model_name='inventoryitem',
name='_name',
),
migrations.RemoveField(
model_name='inventoryitemtemplate',
name='_name',
),
migrations.RemoveField(
model_name='modulebay',
name='_name',
),
migrations.RemoveField(
model_name='modulebaytemplate',
name='_name',
),
migrations.RemoveField(
model_name='poweroutlet',
name='_name',
),
migrations.RemoveField(
model_name='poweroutlettemplate',
name='_name',
),
migrations.RemoveField(
model_name='powerport',
name='_name',
),
migrations.RemoveField(
model_name='powerporttemplate',
name='_name',
),
migrations.RemoveField(
model_name='rack',
name='_name',
),
migrations.RemoveField(
model_name='rearport',
name='_name',
),
migrations.RemoveField(
model_name='rearporttemplate',
name='_name',
),
migrations.RemoveField(
model_name='site',
name='_name',
),
migrations.AlterField(
model_name='consoleport',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='consoleporttemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='consoleserverport',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='consoleserverporttemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='device',
name='name',
field=models.CharField(blank=True, db_collation='natural_sort', max_length=64, null=True),
),
migrations.AlterField(
model_name='devicebay',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='devicebaytemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='frontport',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='frontporttemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='interface',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='interfacetemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='inventoryitem',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='inventoryitemtemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='modulebay',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='modulebaytemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='poweroutlet',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='poweroutlettemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='powerport',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='powerporttemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='rack',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=100),
),
migrations.AlterField(
model_name='rearport',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='rearporttemplate',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 5.0.9 on 2024-11-12 22:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0197_auto_20241112_2221'),
]
operations = [
migrations.AlterModelOptions(
name='site',
options={'ordering': ('name',)},
),
migrations.AlterField(
model_name='site',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=100, unique=True),
),
]

View File

@ -44,12 +44,8 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin):
max_length=64, max_length=64,
help_text=_( help_text=_(
"{module} is accepted as a substitution for the module bay position when attached to a module type." "{module} is accepted as a substitution for the module bay position when attached to a module type."
) ),
) db_collation="natural_sort"
_name = NaturalOrderingField(
target_field='name',
max_length=100,
blank=True
) )
label = models.CharField( label = models.CharField(
verbose_name=_('label'), verbose_name=_('label'),
@ -65,7 +61,7 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin):
class Meta: class Meta:
abstract = True abstract = True
ordering = ('device_type', '_name') ordering = ('device_type', 'name')
constraints = ( constraints = (
models.UniqueConstraint( models.UniqueConstraint(
fields=('device_type', 'name'), fields=('device_type', 'name'),
@ -125,7 +121,7 @@ class ModularComponentTemplateModel(ComponentTemplateModel):
class Meta: class Meta:
abstract = True abstract = True
ordering = ('device_type', 'module_type', '_name') ordering = ('device_type', 'module_type', 'name')
constraints = ( constraints = (
models.UniqueConstraint( models.UniqueConstraint(
fields=('device_type', 'name'), fields=('device_type', 'name'),
@ -782,7 +778,7 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel):
component_model = InventoryItem component_model = InventoryItem
class Meta: class Meta:
ordering = ('device_type__id', 'parent__id', '_name') ordering = ('device_type__id', 'parent__id', 'name')
indexes = ( indexes = (
models.Index(fields=('component_type', 'component_id')), models.Index(fields=('component_type', 'component_id')),
) )

View File

@ -50,12 +50,8 @@ class ComponentModel(NetBoxModel):
) )
name = models.CharField( name = models.CharField(
verbose_name=_('name'), verbose_name=_('name'),
max_length=64 max_length=64,
) db_collation="natural_sort"
_name = NaturalOrderingField(
target_field='name',
max_length=100,
blank=True
) )
label = models.CharField( label = models.CharField(
verbose_name=_('label'), verbose_name=_('label'),
@ -71,7 +67,7 @@ class ComponentModel(NetBoxModel):
class Meta: class Meta:
abstract = True abstract = True
ordering = ('device', '_name') ordering = ('device', 'name')
constraints = ( constraints = (
models.UniqueConstraint( models.UniqueConstraint(
fields=('device', 'name'), fields=('device', 'name'),
@ -1301,7 +1297,7 @@ class InventoryItem(MPTTModel, ComponentModel, TrackingModelMixin):
clone_fields = ('device', 'parent', 'role', 'manufacturer', 'status', 'part_id') clone_fields = ('device', 'parent', 'role', 'manufacturer', 'status', 'part_id')
class Meta: class Meta:
ordering = ('device__id', 'parent__id', '_name') ordering = ('device__id', 'parent__id', 'name')
indexes = ( indexes = (
models.Index(fields=('component_type', 'component_id')), models.Index(fields=('component_type', 'component_id')),
) )

View File

@ -23,7 +23,7 @@ from netbox.config import ConfigItem
from netbox.models import OrganizationalModel, PrimaryModel from netbox.models import OrganizationalModel, PrimaryModel
from netbox.models.mixins import WeightMixin from netbox.models.mixins import WeightMixin
from netbox.models.features import ContactsMixin, ImageAttachmentsMixin from netbox.models.features import ContactsMixin, ImageAttachmentsMixin
from utilities.fields import ColorField, CounterCacheField, NaturalOrderingField from utilities.fields import ColorField, CounterCacheField
from utilities.tracking import TrackingModelMixin from utilities.tracking import TrackingModelMixin
from .device_components import * from .device_components import *
from .mixins import RenderConfigMixin from .mixins import RenderConfigMixin
@ -582,13 +582,8 @@ class Device(
verbose_name=_('name'), verbose_name=_('name'),
max_length=64, max_length=64,
blank=True, blank=True,
null=True null=True,
) db_collation="natural_sort"
_name = NaturalOrderingField(
target_field='name',
max_length=100,
blank=True,
null=True
) )
serial = models.CharField( serial = models.CharField(
max_length=50, max_length=50,
@ -775,7 +770,7 @@ class Device(
) )
class Meta: class Meta:
ordering = ('_name', 'pk') # Name may be null ordering = ('name', 'pk') # Name may be null
constraints = ( constraints = (
models.UniqueConstraint( models.UniqueConstraint(
Lower('name'), 'site', 'tenant', Lower('name'), 'site', 'tenant',

View File

@ -19,7 +19,7 @@ from netbox.models.mixins import WeightMixin
from netbox.models.features import ContactsMixin, ImageAttachmentsMixin from netbox.models.features import ContactsMixin, ImageAttachmentsMixin
from utilities.conversion import to_grams from utilities.conversion import to_grams
from utilities.data import array_to_string, drange from utilities.data import array_to_string, drange
from utilities.fields import ColorField, NaturalOrderingField from utilities.fields import ColorField
from .device_components import PowerPort from .device_components import PowerPort
from .devices import Device, Module from .devices import Device, Module
from .power import PowerFeed from .power import PowerFeed
@ -255,12 +255,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
) )
name = models.CharField( name = models.CharField(
verbose_name=_('name'), verbose_name=_('name'),
max_length=100
)
_name = NaturalOrderingField(
target_field='name',
max_length=100, max_length=100,
blank=True db_collation="natural_sort"
) )
facility_id = models.CharField( facility_id = models.CharField(
max_length=50, max_length=50,
@ -340,7 +336,7 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
) )
class Meta: class Meta:
ordering = ('site', 'location', '_name', 'pk') # (site, location, name) may be non-unique ordering = ('site', 'location', 'name', 'pk') # (site, location, name) may be non-unique
constraints = ( constraints = (
# Name and facility_id must be unique *only* within a Location # Name and facility_id must be unique *only* within a Location
models.UniqueConstraint( models.UniqueConstraint(

View File

@ -8,7 +8,6 @@ from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from netbox.models import NestedGroupModel, PrimaryModel from netbox.models import NestedGroupModel, PrimaryModel
from netbox.models.features import ContactsMixin, ImageAttachmentsMixin from netbox.models.features import ContactsMixin, ImageAttachmentsMixin
from utilities.fields import NaturalOrderingField
__all__ = ( __all__ = (
'Location', 'Location',
@ -146,11 +145,6 @@ class Site(ContactsMixin, ImageAttachmentsMixin, PrimaryModel):
help_text=_("Full name of the site"), help_text=_("Full name of the site"),
db_collation="natural_sort" db_collation="natural_sort"
) )
_name = NaturalOrderingField(
target_field='name',
max_length=100,
blank=True
)
slug = models.SlugField( slug = models.SlugField(
verbose_name=_('slug'), verbose_name=_('slug'),
max_length=100, max_length=100,

View File

@ -5,7 +5,7 @@ from django.db import models
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from utilities.ordering import naturalize from utilities.ordering import naturalize_interface
from .forms.widgets import ColorSelect from .forms.widgets import ColorSelect
from .validators import ColorValidator from .validators import ColorValidator
@ -40,7 +40,7 @@ class NaturalOrderingField(models.CharField):
""" """
description = "Stores a representation of its target field suitable for natural ordering" description = "Stores a representation of its target field suitable for natural ordering"
def __init__(self, target_field, naturalize_function=naturalize, *args, **kwargs): def __init__(self, target_field, naturalize_function=naturalize_interface, *args, **kwargs):
self.target_field = target_field self.target_field = target_field
self.naturalize_function = naturalize_function self.naturalize_function = naturalize_function
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -0,0 +1,37 @@
# Generated by Django 5.0.9 on 2024-11-13 16:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('virtualization', '0045_clusters_cached_relations'),
('dcim', '0197_natural_sort'),
]
operations = [
migrations.AlterModelOptions(
name='virtualmachine',
options={'ordering': ('name', 'pk')},
),
migrations.RemoveField(
model_name='virtualmachine',
name='_name',
),
migrations.AlterField(
model_name='virtualdisk',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='virtualmachine',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
migrations.AlterField(
model_name='vminterface',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=64),
),
]

View File

@ -69,12 +69,8 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co
) )
name = models.CharField( name = models.CharField(
verbose_name=_('name'), verbose_name=_('name'),
max_length=64 max_length=64,
) db_collation="natural_sort"
_name = NaturalOrderingField(
target_field='name',
max_length=100,
blank=True
) )
status = models.CharField( status = models.CharField(
max_length=50, max_length=50,
@ -152,7 +148,7 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co
) )
class Meta: class Meta:
ordering = ('_name', 'pk') # Name may be non-unique ordering = ('name', 'pk') # Name may be non-unique
constraints = ( constraints = (
models.UniqueConstraint( models.UniqueConstraint(
Lower('name'), 'cluster', 'tenant', Lower('name'), 'cluster', 'tenant',
@ -273,7 +269,8 @@ class ComponentModel(NetBoxModel):
) )
name = models.CharField( name = models.CharField(
verbose_name=_('name'), verbose_name=_('name'),
max_length=64 max_length=64,
db_collation="natural_sort"
) )
_name = NaturalOrderingField( _name = NaturalOrderingField(
target_field='name', target_field='name',