Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Generated by Django 5.2 on 2025-07-06 14:47

import uuid

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("event", "0003_alter_event_name_alter_event_name_en_and_more"),
("presentation", "0007_historicalpresentation_summary_and_more"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="CallForPresentationSchedule",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("deleted_at", models.DateTimeField(blank=True, null=True)),
("start_at", models.DateTimeField()),
("end_at", models.DateTimeField()),
(
"created_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_created_by",
to=settings.AUTH_USER_MODEL,
),
),
(
"deleted_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_deleted_by",
to=settings.AUTH_USER_MODEL,
),
),
(
"next_call_for_presentation_schedule",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="presentation.callforpresentationschedule",
),
),
(
"presentation",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="call_for_presentation_schedules",
to="presentation.presentation",
),
),
(
"presentation_type",
models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="presentation.presentationtype"),
),
(
"updated_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_updated_by",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="Room",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("deleted_at", models.DateTimeField(blank=True, null=True)),
("name", models.CharField(max_length=256)),
(
"created_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_created_by",
to=settings.AUTH_USER_MODEL,
),
),
(
"deleted_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_deleted_by",
to=settings.AUTH_USER_MODEL,
),
),
("event", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="event.event")),
(
"updated_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_updated_by",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="RoomSchedule",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("deleted_at", models.DateTimeField(blank=True, null=True)),
("start_at", models.DateTimeField()),
("end_at", models.DateTimeField()),
(
"created_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_created_by",
to=settings.AUTH_USER_MODEL,
),
),
(
"deleted_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_deleted_by",
to=settings.AUTH_USER_MODEL,
),
),
(
"presentation",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="presentation.presentation",
),
),
("room", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="presentation.room")),
(
"updated_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="%(class)s_updated_by",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"abstract": False,
},
),
]
58 changes: 47 additions & 11 deletions app/event/presentation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,31 @@

class PresentationQuerySet(BaseAbstractModelQuerySet):
def get_all_nested_data(self):
return self.filter_active().prefetch_related(
models.Prefetch(
lookup="categories",
queryset=PresentationCategory.objects.filter_active(),
to_attr="_prefetched_active_categories",
),
models.Prefetch(
lookup="speakers",
queryset=PresentationSpeaker.objects.filter_active().select_related("user"),
to_attr="_prefetched_active_speakers",
),
return (
self.filter_active()
.prefetch_related(
models.Prefetch(
lookup="categories",
queryset=PresentationCategory.objects.filter_active(),
to_attr="_prefetched_active_categories",
),
models.Prefetch(
lookup="speakers",
queryset=PresentationSpeaker.objects.filter_active().select_related("user", "image"),
to_attr="_prefetched_active_speakers",
),
models.Prefetch(
lookup="roomschedule_set",
queryset=RoomSchedule.objects.filter_active().select_related("room", "room__event"),
to_attr="_prefetched_active_room_schedules",
),
models.Prefetch(
lookup="call_for_presentation_schedules",
queryset=CallForPresentationSchedule.objects.filter_active().select_related("presentation_type"),
to_attr="_prefetched_active_call_for_presentation_schedules",
),
)
.select_related("image")
)


Expand Down Expand Up @@ -83,3 +97,25 @@ class PresentationSpeaker(BaseAbstractModel):
user = models.ForeignKey(User, on_delete=models.PROTECT)
image = models.ForeignKey(PublicFile, on_delete=models.PROTECT, null=True, blank=True)
biography = MarkdownField(blank=True, default="")


class CallForPresentationSchedule(BaseAbstractModel):
presentation_type = models.ForeignKey(PresentationType, on_delete=models.PROTECT)
presentation = models.ForeignKey(
Presentation, on_delete=models.PROTECT, related_name="call_for_presentation_schedules", null=True, blank=True
)
start_at = models.DateTimeField()
end_at = models.DateTimeField()
next_call_for_presentation_schedule = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True)


class Room(BaseAbstractModel):
event = models.ForeignKey(Event, on_delete=models.PROTECT)
name = models.CharField(max_length=256)


class RoomSchedule(BaseAbstractModel):
room = models.ForeignKey(Room, on_delete=models.PROTECT)
start_at = models.DateTimeField()
end_at = models.DateTimeField()
presentation = models.ForeignKey(Presentation, on_delete=models.PROTECT, null=True, blank=True)
39 changes: 37 additions & 2 deletions app/event/presentation/serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
from event.presentation.models import Presentation, PresentationCategory, PresentationSpeaker
from event.presentation.models import (
CallForPresentationSchedule,
Presentation,
PresentationCategory,
PresentationSpeaker,
RoomSchedule,
)
from rest_framework import serializers


Expand All @@ -17,11 +23,40 @@ class Meta:
fields = ("id", "nickname", "biography", "image")


class RoomScheduleSerializer(serializers.ModelSerializer):
room_name = serializers.CharField(source="room.name", read_only=True)
event_id = serializers.IntegerField(source="room.event.id", read_only=True)
event_name = serializers.CharField(source="room.event.name", read_only=True)

class Meta:
model = RoomSchedule
fields = ("id", "room_name", "event_id", "event_name", "start_at", "end_at")


class CallForPresentationScheduleSerializer(serializers.ModelSerializer):
presentation_type_name = serializers.CharField(source="presentation_type.name", read_only=True)

class Meta:
model = CallForPresentationSchedule
fields = ("id", "presentation_type_name", "start_at", "end_at", "next_call_for_presentation_schedule")


class PresentationSerializer(serializers.ModelSerializer):
image = serializers.FileField(source="image.file", read_only=True, allow_null=True)
categories = PresentationCategorySerializer(many=True, read_only=True)
speakers = PresentationSpeakerSerializer(many=True, read_only=True)
room_schedules = RoomScheduleSerializer(source="room_schedules_set", many=True, read_only=True)
call_for_presentation_schedules = CallForPresentationScheduleSerializer(many=True, read_only=True)

class Meta:
model = Presentation
fields = ("id", "title", "description", "image", "categories", "speakers")
fields = (
"id",
"title",
"description",
"image",
"categories",
"speakers",
"room_schedules",
"call_for_presentation_schedules",
)
28 changes: 28 additions & 0 deletions app/event/presentation/test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import dataclasses
from datetime import datetime, timedelta

import pytest
from event.models import Event
from event.presentation.models import (
CallForPresentationSchedule,
Presentation,
PresentationCategory,
PresentationCategoryRelation,
PresentationSpeaker,
PresentationType,
Room,
RoomSchedule,
)
from faker import Faker
from model_bakery import baker
Expand All @@ -26,6 +30,9 @@ class PresentationTestEntity:
presentation_category: PresentationCategory
presentation_category_relation: PresentationCategoryRelation
presentation_speaker: PresentationSpeaker
room: Room
room_schedule: RoomSchedule
call_for_presentation_schedule: CallForPresentationSchedule


@pytest.fixture
Expand All @@ -47,6 +54,8 @@ def create_event(create_user_with_organization_and_relation):
def create_presentation_set(create_event):
fake = Faker()
user, organization, relation, event = create_event

# 기존 데이터 생성
presentation_type = baker.make(PresentationType, event=event)
presentation = baker.make(Presentation, type=presentation_type)
presentation_category = baker.make(PresentationCategory, type=presentation_type, name=fake.name())
Expand All @@ -55,6 +64,22 @@ def create_presentation_set(create_event):
)
presentation_speaker = baker.make(PresentationSpeaker, presentation=presentation, user=user)

# Room과 RoomSchedule 데이터 생성
room = baker.make(Room, event=event, name=fake.company())
start_time = datetime.now()
room_schedule = baker.make(
RoomSchedule, room=room, presentation=presentation, start_at=start_time, end_at=start_time + timedelta(hours=1)
)

# CallForPresentationSchedule 데이터 생성
cfp_start = start_time - timedelta(days=30)
call_for_presentation_schedule = baker.make(
CallForPresentationSchedule,
presentation_type=presentation_type,
start_at=cfp_start,
end_at=cfp_start + timedelta(days=14),
)

return PresentationTestEntity(
user=user,
organization=organization,
Expand All @@ -64,6 +89,9 @@ def create_presentation_set(create_event):
presentation_category=presentation_category,
presentation_category_relation=presentation_category_relation,
presentation_speaker=presentation_speaker,
room=room,
room_schedule=room_schedule,
call_for_presentation_schedule=call_for_presentation_schedule,
)


Expand Down
2 changes: 1 addition & 1 deletion app/event/presentation/test/count_queries_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ def test_count_queries(
django_assert_max_num_queries: DjangoAssertNumQueries, create_presentation_set: PresentationTestEntity
):
reset_queries()
with django_assert_max_num_queries(3):
with django_assert_max_num_queries(5):
queryset = Presentation.objects.get_all_nested_data()
list(queryset) # query evaluation