diff --git a/netbox/dcim/migrations/0197_auto_20241112_2221.py b/netbox/dcim/migrations/0197_auto_20241112_2221.py deleted file mode 100644 index 02a8e4244..000000000 --- a/netbox/dcim/migrations/0197_auto_20241112_2221.py +++ /dev/null @@ -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", - ), - ] diff --git a/netbox/dcim/migrations/0197_natural_sort.py b/netbox/dcim/migrations/0197_natural_sort.py new file mode 100644 index 000000000..03e81e733 --- /dev/null +++ b/netbox/dcim/migrations/0197_natural_sort.py @@ -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), + ), + ] diff --git a/netbox/dcim/migrations/0198_alter_site_options_alter_site_name.py b/netbox/dcim/migrations/0198_alter_site_options_alter_site_name.py deleted file mode 100644 index 1dbab9cf7..000000000 --- a/netbox/dcim/migrations/0198_alter_site_options_alter_site_name.py +++ /dev/null @@ -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), - ), - ] diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 00555d49e..ddd4d2426 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -44,12 +44,8 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin): max_length=64, help_text=_( "{module} is accepted as a substitution for the module bay position when attached to a module type." - ) - ) - _name = NaturalOrderingField( - target_field='name', - max_length=100, - blank=True + ), + db_collation="natural_sort" ) label = models.CharField( verbose_name=_('label'), @@ -65,7 +61,7 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin): class Meta: abstract = True - ordering = ('device_type', '_name') + ordering = ('device_type', 'name') constraints = ( models.UniqueConstraint( fields=('device_type', 'name'), @@ -125,7 +121,7 @@ class ModularComponentTemplateModel(ComponentTemplateModel): class Meta: abstract = True - ordering = ('device_type', 'module_type', '_name') + ordering = ('device_type', 'module_type', 'name') constraints = ( models.UniqueConstraint( fields=('device_type', 'name'), @@ -782,7 +778,7 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel): component_model = InventoryItem class Meta: - ordering = ('device_type__id', 'parent__id', '_name') + ordering = ('device_type__id', 'parent__id', 'name') indexes = ( models.Index(fields=('component_type', 'component_id')), ) diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 36fd02add..31278a13c 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -50,12 +50,8 @@ class ComponentModel(NetBoxModel): ) name = models.CharField( verbose_name=_('name'), - max_length=64 - ) - _name = NaturalOrderingField( - target_field='name', - max_length=100, - blank=True + max_length=64, + db_collation="natural_sort" ) label = models.CharField( verbose_name=_('label'), @@ -71,7 +67,7 @@ class ComponentModel(NetBoxModel): class Meta: abstract = True - ordering = ('device', '_name') + ordering = ('device', 'name') constraints = ( models.UniqueConstraint( fields=('device', 'name'), @@ -1301,7 +1297,7 @@ class InventoryItem(MPTTModel, ComponentModel, TrackingModelMixin): clone_fields = ('device', 'parent', 'role', 'manufacturer', 'status', 'part_id') class Meta: - ordering = ('device__id', 'parent__id', '_name') + ordering = ('device__id', 'parent__id', 'name') indexes = ( models.Index(fields=('component_type', 'component_id')), ) diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 47f4ee6c9..2cb5ef4f3 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -23,7 +23,7 @@ from netbox.config import ConfigItem from netbox.models import OrganizationalModel, PrimaryModel from netbox.models.mixins import WeightMixin 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 .device_components import * from .mixins import RenderConfigMixin @@ -582,13 +582,8 @@ class Device( verbose_name=_('name'), max_length=64, blank=True, - null=True - ) - _name = NaturalOrderingField( - target_field='name', - max_length=100, - blank=True, - null=True + null=True, + db_collation="natural_sort" ) serial = models.CharField( max_length=50, @@ -775,7 +770,7 @@ class Device( ) class Meta: - ordering = ('_name', 'pk') # Name may be null + ordering = ('name', 'pk') # Name may be null constraints = ( models.UniqueConstraint( Lower('name'), 'site', 'tenant', diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 013dfb619..08b7f5a35 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -19,7 +19,7 @@ from netbox.models.mixins import WeightMixin from netbox.models.features import ContactsMixin, ImageAttachmentsMixin from utilities.conversion import to_grams 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 .devices import Device, Module from .power import PowerFeed @@ -255,12 +255,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): ) name = models.CharField( verbose_name=_('name'), - max_length=100 - ) - _name = NaturalOrderingField( - target_field='name', max_length=100, - blank=True + db_collation="natural_sort" ) facility_id = models.CharField( max_length=50, @@ -340,7 +336,7 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): ) 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 = ( # Name and facility_id must be unique *only* within a Location models.UniqueConstraint( diff --git a/netbox/dcim/models/sites.py b/netbox/dcim/models/sites.py index 442bd8b27..0985a8d7a 100644 --- a/netbox/dcim/models/sites.py +++ b/netbox/dcim/models/sites.py @@ -8,7 +8,6 @@ from dcim.choices import * from dcim.constants import * from netbox.models import NestedGroupModel, PrimaryModel from netbox.models.features import ContactsMixin, ImageAttachmentsMixin -from utilities.fields import NaturalOrderingField __all__ = ( 'Location', @@ -146,11 +145,6 @@ class Site(ContactsMixin, ImageAttachmentsMixin, PrimaryModel): help_text=_("Full name of the site"), db_collation="natural_sort" ) - _name = NaturalOrderingField( - target_field='name', - max_length=100, - blank=True - ) slug = models.SlugField( verbose_name=_('slug'), max_length=100, diff --git a/netbox/utilities/fields.py b/netbox/utilities/fields.py index ee71223cb..c4ea13bc9 100644 --- a/netbox/utilities/fields.py +++ b/netbox/utilities/fields.py @@ -5,7 +5,7 @@ from django.db import models from django.utils.safestring import mark_safe 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 .validators import ColorValidator @@ -40,7 +40,7 @@ class NaturalOrderingField(models.CharField): """ 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.naturalize_function = naturalize_function super().__init__(*args, **kwargs) diff --git a/netbox/virtualization/migrations/0046_alter_virtualmachine_options_and_more.py b/netbox/virtualization/migrations/0046_alter_virtualmachine_options_and_more.py new file mode 100644 index 000000000..8114f7315 --- /dev/null +++ b/netbox/virtualization/migrations/0046_alter_virtualmachine_options_and_more.py @@ -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), + ), + ] diff --git a/netbox/virtualization/models/virtualmachines.py b/netbox/virtualization/models/virtualmachines.py index 4ee41e403..c83d76f02 100644 --- a/netbox/virtualization/models/virtualmachines.py +++ b/netbox/virtualization/models/virtualmachines.py @@ -69,12 +69,8 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co ) name = models.CharField( verbose_name=_('name'), - max_length=64 - ) - _name = NaturalOrderingField( - target_field='name', - max_length=100, - blank=True + max_length=64, + db_collation="natural_sort" ) status = models.CharField( max_length=50, @@ -152,7 +148,7 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co ) class Meta: - ordering = ('_name', 'pk') # Name may be non-unique + ordering = ('name', 'pk') # Name may be non-unique constraints = ( models.UniqueConstraint( Lower('name'), 'cluster', 'tenant', @@ -273,7 +269,8 @@ class ComponentModel(NetBoxModel): ) name = models.CharField( verbose_name=_('name'), - max_length=64 + max_length=64, + db_collation="natural_sort" ) _name = NaturalOrderingField( target_field='name',