From 2aa93a2b51af32a72a688743b4d2c8d1269d4f25 Mon Sep 17 00:00:00 2001 From: ITQ Date: Sun, 16 Feb 2025 12:40:41 +0300 Subject: [PATCH] feat: added mlscore app --- .../services/backend/apps/mlscore/__init__.py | 0 .../services/backend/apps/mlscore/admin.py | 16 +++++ .../services/backend/apps/mlscore/apps.py | 6 ++ .../apps/mlscore/migrations/0001_initial.py | 30 ++++++++ .../apps/mlscore/migrations/__init__.py | 0 .../services/backend/apps/mlscore/models.py | 28 ++++++++ .../services/backend/apps/mlscore/tests.py | 70 +++++++++++++++++++ 7 files changed, 150 insertions(+) create mode 100644 solution/services/backend/apps/mlscore/__init__.py create mode 100644 solution/services/backend/apps/mlscore/admin.py create mode 100644 solution/services/backend/apps/mlscore/apps.py create mode 100644 solution/services/backend/apps/mlscore/migrations/0001_initial.py create mode 100644 solution/services/backend/apps/mlscore/migrations/__init__.py create mode 100644 solution/services/backend/apps/mlscore/models.py create mode 100644 solution/services/backend/apps/mlscore/tests.py diff --git a/solution/services/backend/apps/mlscore/__init__.py b/solution/services/backend/apps/mlscore/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/solution/services/backend/apps/mlscore/admin.py b/solution/services/backend/apps/mlscore/admin.py new file mode 100644 index 0000000..4670384 --- /dev/null +++ b/solution/services/backend/apps/mlscore/admin.py @@ -0,0 +1,16 @@ +from django.contrib import admin + +from apps.mlscore.models import Mlscore + + +class MlscoreAdmin(admin.ModelAdmin): + readonly_fields = (Mlscore.id.field.name,) + fields = ( + Mlscore.id.field.name, + Mlscore.advertiser.field.name, + Mlscore.client.field.name, + Mlscore.score.field.name, + ) + + +admin.site.register(Mlscore, MlscoreAdmin) diff --git a/solution/services/backend/apps/mlscore/apps.py b/solution/services/backend/apps/mlscore/apps.py new file mode 100644 index 0000000..cf96c5b --- /dev/null +++ b/solution/services/backend/apps/mlscore/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MlscoreConfig(AppConfig): + name = "apps.mlscore" + label = "mlscore" diff --git a/solution/services/backend/apps/mlscore/migrations/0001_initial.py b/solution/services/backend/apps/mlscore/migrations/0001_initial.py new file mode 100644 index 0000000..cf660ae --- /dev/null +++ b/solution/services/backend/apps/mlscore/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.6 on 2025-02-14 16:40 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('advertiser', '0001_initial'), + ('client', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Mlscore', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('score', models.PositiveIntegerField()), + ('advertiser', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mlscores', to='advertiser.advertiser')), + ('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mlscores', to='client.client')), + ], + options={ + 'unique_together': {('advertiser', 'client')}, + }, + ), + ] diff --git a/solution/services/backend/apps/mlscore/migrations/__init__.py b/solution/services/backend/apps/mlscore/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/solution/services/backend/apps/mlscore/models.py b/solution/services/backend/apps/mlscore/models.py new file mode 100644 index 0000000..15d65ce --- /dev/null +++ b/solution/services/backend/apps/mlscore/models.py @@ -0,0 +1,28 @@ +from django.db import models + +from apps.advertiser.models import Advertiser +from apps.client.models import Client +from apps.core.models import BaseModel + + +class Mlscore(BaseModel): + advertiser = models.ForeignKey( + Advertiser, + on_delete=models.CASCADE, + related_name="mlscores", + ) + client = models.ForeignKey( + Client, + on_delete=models.CASCADE, + related_name="mlscores", + ) + score = models.PositiveIntegerField() + + def __str__(self) -> str: + return f"{self.advertiser.name} | {self.client.login}" + + class Meta: + unique_together = ( + "advertiser", + "client", + ) diff --git a/solution/services/backend/apps/mlscore/tests.py b/solution/services/backend/apps/mlscore/tests.py new file mode 100644 index 0000000..dc1dd07 --- /dev/null +++ b/solution/services/backend/apps/mlscore/tests.py @@ -0,0 +1,70 @@ +from django.test import TestCase +from django.db.utils import IntegrityError +from django.core.exceptions import ValidationError +from config.errors import ConflictError +from apps.advertiser.models import Advertiser +from apps.client.models import Client +from apps.mlscore.models import Mlscore + + +class MlscoreModelTest(TestCase): + def setUp(self): + self.advertiser = Advertiser.objects.create(name="Test Advertiser") + self.client_obj = Client.objects.create( + login="test_client", + age=25, + location="test_location", + gender=Client.GenderChoices.MALE, + ) + + def test_create_mlscore(self): + mlscore = Mlscore.objects.create( + advertiser=self.advertiser, + client=self.client_obj, + score=95, + ) + + self.assertEqual(mlscore.score, 95) + self.assertEqual(str(mlscore), "Test Advertiser | test_client") + + def test_mlscore_unique_together_constraint(self): + Mlscore.objects.create( + advertiser=self.advertiser, + client=self.client_obj, + score=80, + ) + + with self.assertRaises(ConflictError): + Mlscore.objects.create( + advertiser=self.advertiser, + client=self.client_obj, + score=85, + ) + + def test_delete_advertiser_cascades(self): + mlscore = Mlscore.objects.create( + advertiser=self.advertiser, + client=self.client_obj, + score=90, + ) + self.advertiser.delete() + + self.assertFalse(Mlscore.objects.filter(id=mlscore.id).exists()) + + def test_delete_client_cascades(self): + mlscore = Mlscore.objects.create( + advertiser=self.advertiser, + client=self.client_obj, + score=90, + ) + self.client_obj.delete() + + self.assertFalse(Mlscore.objects.filter(id=mlscore.id).exists()) + + def test_score_positive_integer_constraint(self): + with self.assertRaises(ValidationError): + Mlscore.objects.create( + advertiser=self.advertiser, + client=self.client_obj, + score=-5, + )