diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 97208deaa..763ea038c 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -135,17 +135,17 @@ class RackSerializer(CustomFieldModelSerializer): 'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'serial', 'type', 'width', 'u_height', 'desc_units', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] - # Omit the UniqueTogetherValidator that would be automatically added to validate (site, facility_id). This + # Omit the UniqueTogetherValidator that would be automatically added to validate (group, facility_id). This # prevents facility_id from being interpreted as a required field. validators = [ - UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('site', 'name')) + UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('group', 'name')) ] def validate(self, data): - # Validate uniqueness of (site, facility_id) since we omitted the automatically-created validator from Meta. + # Validate uniqueness of (group, facility_id) since we omitted the automatically-created validator from Meta. if data.get('facility_id', None): - validator = UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('site', 'facility_id')) + validator = UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('group', 'facility_id')) validator.set_context(self) validator(data) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index fe8476d72..49d9500a0 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -354,6 +354,8 @@ class RackCSVForm(forms.ModelForm): site = self.cleaned_data.get('site') group_name = self.cleaned_data.get('group_name') + name = self.cleaned_data.get('name') + facility_id = self.cleaned_data.get('facility_id') # Validate rack group if group_name: @@ -362,6 +364,18 @@ class RackCSVForm(forms.ModelForm): except RackGroup.DoesNotExist: raise forms.ValidationError("Rack group {} not found for site {}".format(group_name, site)) + # Validate uniqueness of rack name within group + if Rack.objects.filter(group=self.instance.group, name=name).exists(): + raise forms.ValidationError( + "A rack named {} already exists within group {}".format(name, group_name) + ) + + # Validate uniqueness of facility ID within group + if facility_id and Rack.objects.filter(group=self.instance.group, facility_id=facility_id).exists(): + raise forms.ValidationError( + "A rack with the facility ID {} already exists within group {}".format(facility_id, group_name) + ) + class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): pk = forms.ModelMultipleChoiceField(queryset=Rack.objects.all(), widget=forms.MultipleHiddenInput) diff --git a/netbox/dcim/migrations/0058_relax_rack_naming_constraints.py b/netbox/dcim/migrations/0058_relax_rack_naming_constraints.py new file mode 100644 index 000000000..e4974be2f --- /dev/null +++ b/netbox/dcim/migrations/0058_relax_rack_naming_constraints.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.12 on 2018-05-22 19:27 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0057_tags'), + ] + + operations = [ + migrations.AlterModelOptions( + name='rack', + options={'ordering': ['site', 'group', 'name']}, + ), + migrations.AlterUniqueTogether( + name='rack', + unique_together=set([('group', 'name'), ('group', 'facility_id')]), + ), + ] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 27d752352..75975437e 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -398,10 +398,10 @@ class Rack(CreatedUpdatedModel, CustomFieldModel): ] class Meta: - ordering = ['site', 'name'] + ordering = ['site', 'group', 'name'] unique_together = [ - ['site', 'name'], - ['site', 'facility_id'], + ['group', 'name'], + ['group', 'facility_id'], ] def __str__(self):