Closes #11279: Replace _name natural key sorting with collation (#18009)

* 11279 add collation

* 11279 add collation

* 11279 add collation

* 11279 add collation

* 11279 fix tables /tests

* 11279 fix tests

* 11279 refactor VirtualDisk

* Clean up migrations

* Misc cleanup

* Correct errant file inclusion

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
Arthur Hanson
2024-11-15 06:32:09 -08:00
committed by GitHub
parent 75aeaab8ee
commit 6ab0792f02
35 changed files with 622 additions and 150 deletions

View File

@@ -25,7 +25,6 @@ class ComponentType(NetBoxObjectType):
"""
Base type for device/VM components
"""
_name: str
virtual_machine: Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')]
@@ -77,7 +76,6 @@ class ClusterTypeType(OrganizationalObjectType):
filters=VirtualMachineFilter
)
class VirtualMachineType(ConfigContextMixin, ContactsMixin, NetBoxObjectType):
_name: str
interface_count: BigInt
virtual_disk_count: BigInt
interface_count: BigInt
@@ -102,6 +100,7 @@ class VirtualMachineType(ConfigContextMixin, ContactsMixin, NetBoxObjectType):
filters=VMInterfaceFilter
)
class VMInterfaceType(IPAddressesMixin, ComponentType):
_name: str
mac_address: str | None
parent: Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')] | None
bridge: Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')] | None

View File

@@ -0,0 +1,43 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('virtualization', '0045_clusters_cached_relations'),
('dcim', '0197_natural_sort_collation'),
]
operations = [
migrations.AlterModelOptions(
name='virtualmachine',
options={'ordering': ('name', 'pk')},
),
migrations.AlterModelOptions(
name='virtualdisk',
options={'ordering': ('virtual_machine', 'name')},
),
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='cluster',
name='name',
field=models.CharField(db_collation='natural_sort', max_length=100),
),
migrations.RemoveField(
model_name='virtualdisk',
name='_name',
),
]

View File

@@ -50,7 +50,8 @@ class Cluster(ContactsMixin, CachedScopeMixin, PrimaryModel):
"""
name = models.CharField(
verbose_name=_('name'),
max_length=100
max_length=100,
db_collation="natural_sort"
)
type = models.ForeignKey(
verbose_name=_('type'),

View File

@@ -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,13 +269,8 @@ class ComponentModel(NetBoxModel):
)
name = models.CharField(
verbose_name=_('name'),
max_length=64
)
_name = NaturalOrderingField(
target_field='name',
naturalize_function=naturalize_interface,
max_length=100,
blank=True
max_length=64,
db_collation="natural_sort"
)
description = models.CharField(
verbose_name=_('description'),
@@ -289,7 +280,6 @@ class ComponentModel(NetBoxModel):
class Meta:
abstract = True
ordering = ('virtual_machine', CollateAsChar('_name'))
constraints = (
models.UniqueConstraint(
fields=('virtual_machine', 'name'),
@@ -311,10 +301,9 @@ class ComponentModel(NetBoxModel):
class VMInterface(ComponentModel, BaseInterface, TrackingModelMixin):
virtual_machine = models.ForeignKey(
to='virtualization.VirtualMachine',
on_delete=models.CASCADE,
related_name='interfaces' # Override ComponentModel
name = models.CharField(
verbose_name=_('name'),
max_length=64,
)
_name = NaturalOrderingField(
target_field='name',
@@ -322,6 +311,11 @@ class VMInterface(ComponentModel, BaseInterface, TrackingModelMixin):
max_length=100,
blank=True
)
virtual_machine = models.ForeignKey(
to='virtualization.VirtualMachine',
on_delete=models.CASCADE,
related_name='interfaces' # Override ComponentModel
)
ip_addresses = GenericRelation(
to='ipam.IPAddress',
content_type_field='assigned_object_type',
@@ -358,6 +352,7 @@ class VMInterface(ComponentModel, BaseInterface, TrackingModelMixin):
class Meta(ComponentModel.Meta):
verbose_name = _('interface')
verbose_name_plural = _('interfaces')
ordering = ('virtual_machine', CollateAsChar('_name'))
def clean(self):
super().clean()
@@ -416,3 +411,4 @@ class VirtualDisk(ComponentModel, TrackingModelMixin):
class Meta(ComponentModel.Meta):
verbose_name = _('virtual disk')
verbose_name_plural = _('virtual disks')
ordering = ('virtual_machine', 'name')

View File

@@ -53,7 +53,6 @@ VMINTERFACE_BUTTONS = """
class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.Column(
verbose_name=_('Name'),
order_by=('_name',),
linkify=True
)
status = columns.ChoiceFieldColumn(