Skip to content

Commit db03a5c

Browse files
committed
feat: SponsorTag 추가
1 parent 3cbb1d5 commit db03a5c

File tree

7 files changed

+141
-48
lines changed

7 files changed

+141
-48
lines changed
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from core.const.serializer import COMMON_ADMIN_FIELDS
22
from core.serializer.base_abstract_serializer import BaseAbstractSerializer
33
from core.serializer.json_schema_serializer import JsonSchemaSerializer
4-
from event.sponsor.models import Sponsor, SponsorTier
4+
from event.sponsor.models import Sponsor, SponsorTag, SponsorTier
55
from rest_framework import serializers
66

77

@@ -11,9 +11,16 @@ class Meta:
1111
fields = COMMON_ADMIN_FIELDS + ("event", "name_ko", "name_en", "order")
1212

1313

14+
class SponsorTagAdminSerializer(BaseAbstractSerializer, JsonSchemaSerializer, serializers.ModelSerializer):
15+
class Meta:
16+
model = SponsorTag
17+
fields = COMMON_ADMIN_FIELDS + ("event", "name_ko", "name_en")
18+
19+
1420
class SponsorAdminSerializer(BaseAbstractSerializer, JsonSchemaSerializer, serializers.ModelSerializer):
15-
sponsor_tiers = serializers.PrimaryKeyRelatedField(many=True, queryset=SponsorTier.objects.filter_active())
21+
tiers = serializers.PrimaryKeyRelatedField(many=True, queryset=SponsorTier.objects.filter_active())
22+
tags = serializers.PrimaryKeyRelatedField(many=True, queryset=SponsorTag.objects.filter_active())
1623

1724
class Meta:
1825
model = Sponsor
19-
fields = COMMON_ADMIN_FIELDS + ("event", "logo", "sitemap", "name_ko", "name_en", "sponsor_tiers")
26+
fields = COMMON_ADMIN_FIELDS + ("event", "logo", "sitemap", "name_ko", "name_en", "tiers", "tags")

app/admin_api/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
PresentationSpeakerAdminViewSet,
66
PresentationTypeAdminViewSet,
77
)
8-
from admin_api.views.event.sponsor import SponsorAdminViewSet, SponsorTierAdminViewSet
8+
from admin_api.views.event.sponsor import SponsorAdminViewSet, SponsorTagAdminViewSet, SponsorTierAdminViewSet
99
from admin_api.views.file import PublicFileAdminViewSet
1010
from admin_api.views.user import OrganizationAdminViewSet, UserAdminViewSet
1111
from django.urls import include, path
@@ -25,6 +25,7 @@
2525
admin_event_router = routers.SimpleRouter()
2626
admin_event_router.register("event", EventAdminViewSet)
2727
admin_event_router.register("sponsortier", SponsorTierAdminViewSet)
28+
admin_event_router.register("sponsortag", SponsorTagAdminViewSet)
2829
admin_event_router.register("sponsor", SponsorAdminViewSet)
2930
admin_event_router.register("presentationtype", PresentationTypeAdminViewSet)
3031
admin_event_router.register("presentation", PresentationAdminViewSet)
Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
from __future__ import annotations
22

3-
from admin_api.serializers.event.sponsor import SponsorAdminSerializer, SponsorTierAdminSerializer
4-
from core.const.regex import UUID_V4_PATTERN
3+
from admin_api.serializers.event.sponsor import (
4+
SponsorAdminSerializer,
5+
SponsorTagAdminSerializer,
6+
SponsorTierAdminSerializer,
7+
)
58
from core.const.tag import OpenAPITag
69
from core.permissions import IsSuperUser
710
from core.viewset.json_schema_viewset import JsonSchemaViewSet
811
from django.db import models
912
from drf_spectacular.utils import extend_schema, extend_schema_view
10-
from event.sponsor.models import Sponsor, SponsorTier, SponsorTierSponsorRelation
11-
from rest_framework import decorators, exceptions, response, status, viewsets
13+
from event.sponsor.models import Sponsor, SponsorTag, SponsorTier
14+
from rest_framework import viewsets
1215

1316
ADMIN_METHODS = ["list", "retrieve", "create", "update", "partial_update", "destroy"]
1417

@@ -30,33 +33,13 @@ class SponsorTierAdminViewSet(JsonSchemaViewSet, viewsets.ModelViewSet):
3033
.select_related("created_by", "updated_by", "deleted_by")
3134
)
3235

33-
@extend_schema(
34-
tags=[OpenAPITag.ADMIN_EVENT_SPONSOR],
35-
responses={status.HTTP_200_OK: SponsorAdminSerializer(many=True)},
36-
)
37-
@decorators.action(detail=True, methods=["get"], url_path="sponsors")
38-
def list_sponsors(self, *args: tuple, **kwargs: dict) -> response.Response:
39-
tier: SponsorTier = self.get_object()
40-
return response.Response(data=SponsorAdminSerializer(instance=tier.active_sponsors, many=True).data)
41-
42-
@extend_schema(tags=[OpenAPITag.ADMIN_EVENT_SPONSOR], responses={status.HTTP_201_CREATED: SponsorAdminSerializer})
43-
@decorators.action(detail=True, methods=["post"], url_path=f"sponsors/(?P<sponsor_id>{UUID_V4_PATTERN})")
44-
def add_sponsor(self, sponsor_id: str, *args: tuple, **kwargs: dict) -> response.Response:
45-
tier: SponsorTier = self.get_object()
46-
if not (sponsor := Sponsor.objects.filter_active().filter(id=sponsor_id).first()):
47-
raise exceptions.NotFound(detail="Sponsor not found")
48-
49-
SponsorTierSponsorRelation.objects.get_or_create(tier=tier, sponsor=sponsor)
50-
return response.Response(data=SponsorAdminSerializer(instance=sponsor).data, status=status.HTTP_201_CREATED)
5136

52-
@extend_schema(tags=[OpenAPITag.ADMIN_EVENT_SPONSOR], responses={status.HTTP_204_NO_CONTENT: None})
53-
@decorators.action(detail=True, methods=["delete"], url_path=f"sponsors/(?P<sponsor_id>{UUID_V4_PATTERN})")
54-
def remove_sponsor(self, pk: str, sponsor_id: str, *args: tuple, **kwargs: dict) -> response.Response:
55-
if not (relation := SponsorTierSponsorRelation.objects.filter(tier_id=pk, sponsor_id=sponsor_id).first()):
56-
raise exceptions.NotFound(detail="Sponsor is not associated with this tier")
57-
58-
relation.delete()
59-
return response.Response(status=status.HTTP_204_NO_CONTENT)
37+
@extend_schema_view(**{m: extend_schema(tags=[OpenAPITag.ADMIN_EVENT_SPONSOR]) for m in ADMIN_METHODS})
38+
class SponsorTagAdminViewSet(JsonSchemaViewSet, viewsets.ModelViewSet):
39+
http_method_names = ["get", "post", "patch", "delete"]
40+
serializer_class = SponsorTagAdminSerializer
41+
permission_classes = [IsSuperUser]
42+
queryset = SponsorTag.objects.filter_active().select_related("created_by", "updated_by", "deleted_by")
6043

6144

6245
@extend_schema_view(**{m: extend_schema(tags=[OpenAPITag.ADMIN_EVENT_SPONSOR]) for m in ADMIN_METHODS})
@@ -65,14 +48,3 @@ class SponsorAdminViewSet(JsonSchemaViewSet, viewsets.ModelViewSet):
6548
serializer_class = SponsorAdminSerializer
6649
permission_classes = [IsSuperUser]
6750
queryset = Sponsor.objects.filter_active().select_related("created_by", "updated_by", "deleted_by")
68-
69-
@extend_schema(
70-
tags=[OpenAPITag.ADMIN_EVENT_SPONSOR],
71-
responses={status.HTTP_200_OK: SponsorTierAdminSerializer(many=True)},
72-
)
73-
@decorators.action(detail=True, methods=["get"], url_path="tiers")
74-
def list_tiers(self, *args: tuple, **kwargs: dict) -> response.Response:
75-
sponsor: Sponsor = self.get_object()
76-
tier_id_qs = SponsorTierSponsorRelation.objects.filter(sponsor=sponsor).values_list("tier_id", flat=True)
77-
tiers = SponsorTier.objects.filter_active().filter(id__in=tier_id_qs)
78-
return response.Response(data=SponsorTierAdminSerializer(instance=tiers, many=True).data)

app/event/sponsor/migrations/0007_sponsor_sponsor_tiers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class Migration(migrations.Migration):
1111
operations = [
1212
migrations.AddField(
1313
model_name="sponsor",
14-
name="sponsor_tiers",
14+
name="tiers",
1515
field=models.ManyToManyField(through="sponsor.SponsorTierSponsorRelation", to="sponsor.sponsortier"),
1616
),
1717
]
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Generated by Django 5.2 on 2025-06-20 07:55
2+
3+
import uuid
4+
5+
import core.fields
6+
import django.db.models.deletion
7+
from django.conf import settings
8+
from django.db import migrations, models
9+
10+
11+
class Migration(migrations.Migration):
12+
dependencies = [
13+
("event", "0003_alter_event_name_alter_event_name_en_and_more"),
14+
("sponsor", "0007_sponsor_sponsor_tiers"),
15+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
16+
]
17+
18+
operations = [
19+
migrations.CreateModel(
20+
name="SponsorTag",
21+
fields=[
22+
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
23+
("created_at", models.DateTimeField(auto_now_add=True)),
24+
("updated_at", models.DateTimeField(auto_now=True)),
25+
("deleted_at", models.DateTimeField(blank=True, null=True)),
26+
("name", models.CharField(max_length=256)),
27+
(
28+
"created_by",
29+
models.ForeignKey(
30+
null=True,
31+
on_delete=django.db.models.deletion.PROTECT,
32+
related_name="%(class)s_created_by",
33+
to=settings.AUTH_USER_MODEL,
34+
),
35+
),
36+
(
37+
"deleted_by",
38+
models.ForeignKey(
39+
null=True,
40+
on_delete=django.db.models.deletion.PROTECT,
41+
related_name="%(class)s_deleted_by",
42+
to=settings.AUTH_USER_MODEL,
43+
),
44+
),
45+
("event", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="event.event")),
46+
(
47+
"updated_by",
48+
models.ForeignKey(
49+
null=True,
50+
on_delete=django.db.models.deletion.PROTECT,
51+
related_name="%(class)s_updated_by",
52+
to=settings.AUTH_USER_MODEL,
53+
),
54+
),
55+
],
56+
options={
57+
"ordering": ["name"],
58+
},
59+
),
60+
migrations.CreateModel(
61+
name="SponsorTagRelation",
62+
fields=[
63+
(
64+
"id",
65+
core.fields.UUIDAutoField(
66+
auto_created=True,
67+
default=uuid.uuid4,
68+
editable=False,
69+
primary_key=True,
70+
serialize=False,
71+
verbose_name="ID",
72+
),
73+
),
74+
("sponsor", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="sponsor.sponsor")),
75+
("tag", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="sponsor.sponsortag")),
76+
],
77+
),
78+
migrations.AddField(
79+
model_name="sponsor",
80+
name="tags",
81+
field=models.ManyToManyField(through="sponsor.SponsorTagRelation", to="sponsor.sponsortag"),
82+
),
83+
migrations.AddConstraint(
84+
model_name="sponsortag",
85+
constraint=models.UniqueConstraint(fields=("name",), name="uq__spsr_tag__name"),
86+
),
87+
migrations.AddConstraint(
88+
model_name="sponsortagrelation",
89+
constraint=models.UniqueConstraint(fields=("sponsor", "tag"), name="uq__spsr_tag_rel__spsr_tag"),
90+
),
91+
]

app/event/sponsor/models.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class Sponsor(BaseAbstractModel):
1414
logo = models.ForeignKey(to="file.PublicFile", on_delete=models.PROTECT)
1515
sitemap = models.ForeignKey(to="cms.Sitemap", on_delete=models.PROTECT, null=True, blank=True)
1616

17-
sponsor_tiers = models.ManyToManyField(to="SponsorTier", through="SponsorTierSponsorRelation")
17+
tiers = models.ManyToManyField(to="SponsorTier", through="SponsorTierSponsorRelation")
18+
tags = models.ManyToManyField(to="SponsorTag", through="SponsorTagRelation")
1819

1920
class Meta:
2021
ordering = ["name"]
@@ -55,3 +56,23 @@ class SponsorTierSponsorRelation(models.Model):
5556

5657
class Meta:
5758
constraints = [models.UniqueConstraint(fields=["tier", "sponsor"], name="uq__spsr_tier_rel__tier_spsr")]
59+
60+
61+
class SponsorTag(BaseAbstractModel):
62+
event = models.ForeignKey(Event, on_delete=models.PROTECT)
63+
name = models.CharField(max_length=256)
64+
65+
class Meta:
66+
ordering = ["name"]
67+
constraints = [models.UniqueConstraint(fields=["name"], name="uq__spsr_tag__name")]
68+
69+
def __str__(self) -> str:
70+
return self.name
71+
72+
73+
class SponsorTagRelation(models.Model):
74+
sponsor = models.ForeignKey(Sponsor, on_delete=models.CASCADE)
75+
tag = models.ForeignKey(SponsorTag, on_delete=models.CASCADE)
76+
77+
class Meta:
78+
constraints = [models.UniqueConstraint(fields=["sponsor", "tag"], name="uq__spsr_tag_rel__spsr_tag")]

app/event/sponsor/serializers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
class SponsorSerializer(serializers.ModelSerializer):
66
logo = serializers.FileField(source="logo.file", read_only=True)
7+
tags = serializers.StringRelatedField(many=True, read_only=True)
78

89
class Meta:
910
model = Sponsor
10-
fields = ("id", "name", "logo", "sitemap_id")
11+
fields = ("id", "name", "logo", "sitemap_id", "tags")
1112

1213

1314
class SponsorTierSerializer(serializers.ModelSerializer):

0 commit comments

Comments
 (0)