diff --git a/netbox/ipam/models/vlans.py b/netbox/ipam/models/vlans.py index 91e39c6d3..8ebefe083 100644 --- a/netbox/ipam/models/vlans.py +++ b/netbox/ipam/models/vlans.py @@ -1,4 +1,5 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation +from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.fields import ArrayField, IntegerRangeField from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator @@ -6,7 +7,7 @@ from django.db import models from django.db.backends.postgresql.psycopg_any import NumericRange from django.utils.translation import gettext_lazy as _ -from dcim.models import Interface +from dcim.models import Interface, Site, SiteGroup from ipam.choices import * from ipam.constants import * from ipam.querysets import VLANQuerySet, VLANGroupQuerySet @@ -279,12 +280,20 @@ class VLAN(PrimaryModel): super().clean() # Validate VLAN group (if assigned) - if self.group and self.site and self.group.scope != self.site: - raise ValidationError( - _( - "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to site {site}." - ).format(group=self.group, scope=self.group.scope, site=self.site) - ) + if self.group and self.site and self.group.scope_type == ContentType.objects.get_for_model(Site): + if self.site != self.group.scope: + raise ValidationError( + _( + "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to site {site}." + ).format(group=self.group, scope=self.group.scope, site=self.site) + ) + if self.group and self.site and self.group.scope_type == ContentType.objects.get_for_model(SiteGroup): + if self.site not in self.group.scope.sites.all(): + raise ValidationError( + _( + "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to site {site}." + ).format(group=self.group, scope=self.group.scope, site=self.site) + ) # Check that the VLAN ID is permitted in the assigned group (if any) if self.group: