#3851 - Fix for Suborg/Portfolio unique constraints for portfolio and non-unique for suborg - [ad] (#3921)

* fix for error

* fix for migration

* updated message

* added unique constraints

* ran the formmatter

* updated the tests

* misspelling

* added a drop constraint

* ran the formatter

* added the reverse sql

* redid migration

---------

Co-authored-by: CuriousX <nicolle.leclair@gmail.com>
This commit is contained in:
asaki222 2025-06-30 16:20:55 -04:00 committed by GitHub
parent b7ea0faff1
commit af9e9f337b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 13 deletions

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.20 on 2025-06-24 14:16 # Generated by Django 4.2.20 on 2025-06-30 19:30
from django.db import migrations, models from django.db import migrations, models
@ -20,4 +20,8 @@ class Migration(migrations.Migration):
name="name", name="name",
field=models.CharField(max_length=1000, verbose_name="Suborganization"), field=models.CharField(max_length=1000, verbose_name="Suborganization"),
), ),
migrations.AddConstraint(
model_name="suborganization",
constraint=models.UniqueConstraint(fields=("name", "portfolio"), name="unique_name_portfolio"),
),
] ]

View file

@ -12,6 +12,7 @@ class Suborganization(TimeStampedModel):
class Meta: class Meta:
ordering = ["name"] ordering = ["name"]
constraints = [models.UniqueConstraint(fields=["name", "portfolio"], name="unique_name_portfolio")]
name = models.CharField( name = models.CharField(
max_length=1000, max_length=1000,
@ -49,7 +50,7 @@ class Suborganization(TimeStampedModel):
) )
.exists() .exists()
): ):
raise ValidationError({"name": "Name already exists in Portfolio"}) raise ValidationError({"name": "Suborganization name already exists in Portfolio"})
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
super().save(*args, **kwargs) super().save(*args, **kwargs)

View file

@ -73,9 +73,7 @@ from registrar.models.utility.portfolio_helper import UserPortfolioPermissionCho
from django.contrib.sessions.backends.db import SessionStore from django.contrib.sessions.backends.db import SessionStore
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib import messages from django.contrib import messages
from django.db import transaction from django.db import transaction, IntegrityError
from django.core.exceptions import ValidationError
from unittest.mock import ANY, call, patch, Mock from unittest.mock import ANY, call, patch, Mock
import logging import logging
@ -4185,14 +4183,19 @@ class TestPortfolioAdmin(TestCase):
suborg_names = [li.text for li in soup.find_all("li")] suborg_names = [li.text for li in soup.find_all("li")]
self.assertEqual(suborg_names, ["Sub1", "Sub2", "Sub3", "Sub4", "Sub5"]) self.assertEqual(suborg_names, ["Sub1", "Sub2", "Sub3", "Sub4", "Sub5"])
def test_can_have_dup_suborganizatons(self): def test_cannot_have_dup_suborganizations_with_same_portfolio(self):
portfolio = Portfolio.objects.create(organization_name="Test portfolio too", creator=self.superuser) portfolio = Portfolio.objects.create(organization_name="Test portfolio too", creator=self.superuser)
Suborganization.objects.create(name="Sub1", portfolio=portfolio) Suborganization.objects.create(name="Sub1", portfolio=portfolio)
Suborganization.objects.create(name="Sub1", portfolio=portfolio) with self.assertRaises(IntegrityError):
with transaction.atomic():
Suborganization.objects.create(name="Sub1", portfolio=portfolio)
with self.assertRaises(ValidationError): def test_can_have_dup_suborganizations_with_diff_portfolio(self):
test_dup = Suborganization(name="sub1", portfolio=portfolio) portfolio = Portfolio.objects.create(organization_name="Test portfolio too", creator=self.superuser)
test_dup.full_clean() Suborganization.objects.create(name="Sub1", portfolio=portfolio)
Suborganization.objects.create(name="Sub1", portfolio=self.portfolio)
num_of_subs = Suborganization.objects.filter(name="Sub1").count()
self.assertEqual(num_of_subs, 2)
@less_console_noise_decorator @less_console_noise_decorator
def test_domains_display(self): def test_domains_display(self):
@ -4352,10 +4355,9 @@ class TestPortfolioAdmin(TestCase):
@less_console_noise_decorator @less_console_noise_decorator
def test_duplicate_portfolio(self): def test_duplicate_portfolio(self):
with self.assertRaises(ValidationError): with self.assertRaises(IntegrityError):
with transaction.atomic(): with transaction.atomic():
portfolio_dup = Portfolio(organization_name="Test portfolio", creator=self.superuser) Portfolio.objects.create(organization_name="Test portfolio", creator=self.superuser)
portfolio_dup.full_clean()
class TestTransferUser(WebTest): class TestTransferUser(WebTest):