Skip to content

Commit 8e2bb47

Browse files
authored
Merge pull request #19 from pythonkr/feature/presentation-model-api
Feat: event, presentation app & model & list API 개발
2 parents e63ac69 + 1a7ac71 commit 8e2bb47

32 files changed

+1483
-29
lines changed

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,18 @@ local-makemigrations:
6868
local-migrate:
6969
@ENV_PATH=envfile/.env.local uv run python app/manage.py migrate
7070

71+
# Show django makemigrations
72+
local-showmigrations:
73+
@ENV_PATH=envfile/.env.local uv run python app/manage.py showmigrations
74+
7175
# Create admin superuser
7276
local-createsuperuser:
7377
@ENV_PATH=envfile/.env.local uv run python app/manage.py createsuperuser
7478

79+
# Reverse django migrations
80+
local-reverse-migrations:
81+
@ENV_PATH=envfile/.env.local uv run python app/manage.py migrate $(app) $(number)
82+
7583
# Run pytest
7684
local-test:
7785
@ENV_PATH=envfile/.env.local cd app && uv run pytest -v

app/core/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@
157157
"user",
158158
"file",
159159
"cms",
160+
"event",
161+
"event.presentation",
160162
"admin_api",
161163
# django-constance
162164
"constance",

app/core/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424

2525
# type: ignore[assignment]
2626
v1_apis: list[resolvers.URLPattern | resolvers.URLResolver] = [
27-
path("admin-api/", include("admin_api.urls")),
2827
path("cms/", include("cms.urls")),
28+
path("admin-api/", include("admin_api.urls")),
29+
path("event/presentations/", include("event.presentation.urls")),
2930
]
3031

3132
urlpatterns = [

app/event/__init__.py

Whitespace-only changes.

app/event/admin.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Register your models here.

app/event/apps.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import importlib
2+
3+
from django.apps import AppConfig
4+
5+
6+
class EventConfig(AppConfig):
7+
name = "event"
8+
9+
def ready(self):
10+
importlib.import_module("event.translation")
11+
12+
from event.models import Event
13+
from simple_history import register
14+
15+
register(Event)
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# Generated by Django 5.2 on 2025-06-05 11:04
2+
3+
import uuid
4+
5+
import django.db.models.deletion
6+
import simple_history.models
7+
from django.conf import settings
8+
from django.db import migrations, models
9+
10+
11+
class Migration(migrations.Migration):
12+
initial = True
13+
14+
dependencies = [
15+
("user", "0002_organization_historicalorganization_and_more"),
16+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
17+
]
18+
19+
operations = [
20+
migrations.CreateModel(
21+
name="Event",
22+
fields=[
23+
(
24+
"id",
25+
models.UUIDField(
26+
default=uuid.uuid4,
27+
editable=False,
28+
primary_key=True,
29+
serialize=False,
30+
),
31+
),
32+
("created_at", models.DateTimeField(auto_now_add=True)),
33+
("updated_at", models.DateTimeField(auto_now=True)),
34+
("deleted_at", models.DateTimeField(blank=True, null=True)),
35+
("name", models.CharField(blank=True, max_length=256, null=True)),
36+
("name_ko", models.CharField(blank=True, max_length=256, null=True)),
37+
("name_en", models.CharField(blank=True, max_length=256, null=True)),
38+
("banner_image", models.TextField(blank=True, null=True)),
39+
("slogan", models.CharField(blank=True, max_length=1000, null=True)),
40+
("slogan_ko", models.CharField(blank=True, max_length=1000, null=True)),
41+
("slogan_en", models.CharField(blank=True, max_length=1000, null=True)),
42+
(
43+
"description",
44+
models.CharField(blank=True, max_length=1000, null=True),
45+
),
46+
(
47+
"description_ko",
48+
models.CharField(blank=True, max_length=1000, null=True),
49+
),
50+
(
51+
"description_en",
52+
models.CharField(blank=True, max_length=1000, null=True),
53+
),
54+
("event_start_at", models.DateTimeField(blank=True, null=True)),
55+
("event_end_at", models.DateTimeField(blank=True, null=True)),
56+
(
57+
"banner_display_start_at",
58+
models.DateTimeField(blank=True, null=True),
59+
),
60+
("banner_display_end_at", models.DateTimeField(blank=True, null=True)),
61+
(
62+
"created_by",
63+
models.ForeignKey(
64+
null=True,
65+
on_delete=django.db.models.deletion.PROTECT,
66+
related_name="%(class)s_created_by",
67+
to=settings.AUTH_USER_MODEL,
68+
),
69+
),
70+
(
71+
"deleted_by",
72+
models.ForeignKey(
73+
null=True,
74+
on_delete=django.db.models.deletion.PROTECT,
75+
related_name="%(class)s_deleted_by",
76+
to=settings.AUTH_USER_MODEL,
77+
),
78+
),
79+
(
80+
"organization",
81+
models.ForeignKey(
82+
on_delete=django.db.models.deletion.PROTECT,
83+
related_name="events",
84+
to="user.organization",
85+
),
86+
),
87+
(
88+
"updated_by",
89+
models.ForeignKey(
90+
null=True,
91+
on_delete=django.db.models.deletion.PROTECT,
92+
related_name="%(class)s_updated_by",
93+
to=settings.AUTH_USER_MODEL,
94+
),
95+
),
96+
],
97+
options={
98+
"abstract": False,
99+
},
100+
),
101+
migrations.CreateModel(
102+
name="HistoricalEvent",
103+
fields=[
104+
(
105+
"id",
106+
models.UUIDField(db_index=True, default=uuid.uuid4, editable=False),
107+
),
108+
("created_at", models.DateTimeField(blank=True, editable=False)),
109+
("updated_at", models.DateTimeField(blank=True, editable=False)),
110+
("deleted_at", models.DateTimeField(blank=True, null=True)),
111+
("name", models.CharField(blank=True, max_length=256, null=True)),
112+
("name_ko", models.CharField(blank=True, max_length=256, null=True)),
113+
("name_en", models.CharField(blank=True, max_length=256, null=True)),
114+
("banner_image", models.TextField(blank=True, null=True)),
115+
("slogan", models.CharField(blank=True, max_length=1000, null=True)),
116+
("slogan_ko", models.CharField(blank=True, max_length=1000, null=True)),
117+
("slogan_en", models.CharField(blank=True, max_length=1000, null=True)),
118+
(
119+
"description",
120+
models.CharField(blank=True, max_length=1000, null=True),
121+
),
122+
(
123+
"description_ko",
124+
models.CharField(blank=True, max_length=1000, null=True),
125+
),
126+
(
127+
"description_en",
128+
models.CharField(blank=True, max_length=1000, null=True),
129+
),
130+
("event_start_at", models.DateTimeField(blank=True, null=True)),
131+
("event_end_at", models.DateTimeField(blank=True, null=True)),
132+
(
133+
"banner_display_start_at",
134+
models.DateTimeField(blank=True, null=True),
135+
),
136+
("banner_display_end_at", models.DateTimeField(blank=True, null=True)),
137+
("history_id", models.AutoField(primary_key=True, serialize=False)),
138+
("history_date", models.DateTimeField(db_index=True)),
139+
("history_change_reason", models.CharField(max_length=100, null=True)),
140+
(
141+
"history_type",
142+
models.CharField(
143+
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
144+
max_length=1,
145+
),
146+
),
147+
(
148+
"created_by",
149+
models.ForeignKey(
150+
blank=True,
151+
db_constraint=False,
152+
null=True,
153+
on_delete=django.db.models.deletion.DO_NOTHING,
154+
related_name="+",
155+
to=settings.AUTH_USER_MODEL,
156+
),
157+
),
158+
(
159+
"deleted_by",
160+
models.ForeignKey(
161+
blank=True,
162+
db_constraint=False,
163+
null=True,
164+
on_delete=django.db.models.deletion.DO_NOTHING,
165+
related_name="+",
166+
to=settings.AUTH_USER_MODEL,
167+
),
168+
),
169+
(
170+
"history_user",
171+
models.ForeignKey(
172+
null=True,
173+
on_delete=django.db.models.deletion.SET_NULL,
174+
related_name="+",
175+
to=settings.AUTH_USER_MODEL,
176+
),
177+
),
178+
(
179+
"organization",
180+
models.ForeignKey(
181+
blank=True,
182+
db_constraint=False,
183+
null=True,
184+
on_delete=django.db.models.deletion.DO_NOTHING,
185+
related_name="+",
186+
to="user.organization",
187+
),
188+
),
189+
(
190+
"updated_by",
191+
models.ForeignKey(
192+
blank=True,
193+
db_constraint=False,
194+
null=True,
195+
on_delete=django.db.models.deletion.DO_NOTHING,
196+
related_name="+",
197+
to=settings.AUTH_USER_MODEL,
198+
),
199+
),
200+
],
201+
options={
202+
"verbose_name": "historical event",
203+
"verbose_name_plural": "historical events",
204+
"ordering": ("-history_date", "-history_id"),
205+
"get_latest_by": ("history_date", "history_id"),
206+
},
207+
bases=(simple_history.models.HistoricalChanges, models.Model),
208+
),
209+
]

app/event/migrations/__init__.py

Whitespace-only changes.

app/event/models.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from core.models import BaseAbstractModel
2+
from django.core.exceptions import ValidationError
3+
from django.db import models
4+
from user.models import Organization
5+
6+
7+
class Event(BaseAbstractModel):
8+
organization = models.ForeignKey(Organization, on_delete=models.PROTECT, related_name="events")
9+
name = models.CharField(max_length=256, null=True, blank=True)
10+
banner_image = models.TextField(null=True, blank=True)
11+
slogan = models.CharField(max_length=1000, null=True, blank=True)
12+
description = models.CharField(max_length=1000, null=True, blank=True)
13+
event_start_at = models.DateTimeField(null=True, blank=True)
14+
event_end_at = models.DateTimeField(null=True, blank=True)
15+
banner_display_start_at = models.DateTimeField(null=True, blank=True)
16+
banner_display_end_at = models.DateTimeField(null=True, blank=True)
17+
18+
def clean(self) -> None:
19+
super().clean()
20+
if self.event_start_at and self.event_end_at and self.event_start_at > self.event_end_at:
21+
raise ValidationError("event의 종료 날짜는 시작 날짜보다 이전일 수 없습니다.")
22+
if (
23+
self.banner_display_start_at
24+
and self.banner_display_end_at
25+
and self.banner_display_start_at > self.banner_display_end_at
26+
):
27+
raise ValidationError("banner 전시 종료 날짜는 시작 날짜보다 이전일 수 없습니다.")

app/event/presentation/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)