Skip to content

Commit e0cf830

Browse files
authored
Merge pull request #9 from golony6449/feature/register-app-sponsor
후원사 django app 생성
2 parents 6dea40d + 818b131 commit e0cf830

File tree

13 files changed

+198
-2
lines changed

13 files changed

+198
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/.idea
22
/db.sqlite3
3+
/sponsor/migrations

pyconkr/settings-dev.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
}
1717

1818
# django-storages: S3
19+
del MEDIA_ROOT
1920
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
2021
STATICFILES_STORAGE = "storages.backends.s3boto3.S3StaticStorage"
2122
AWS_S3_ACCESS_KEY_ID = os.getenv("AWS_S3_ACCESS_KEY_ID")

pyconkr/settings-prod.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
}
1717

1818
# django-storages: S3
19+
del MEDIA_ROOT
1920
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
2021
STATICFILES_STORAGE = "storages.backends.s3boto3.S3StaticStorage"
2122
AWS_S3_ACCESS_KEY_ID = os.getenv("AWS_S3_ACCESS_KEY_ID")

pyconkr/settings.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@
3737
"django.contrib.sessions",
3838
"django.contrib.messages",
3939
"django.contrib.staticfiles",
40-
# djangorestframework
40+
41+
# add-on
4142
"rest_framework",
43+
"django_summernote"
44+
45+
# apps
46+
"sponsor",
4247
]
4348

4449
MIDDLEWARE = [
@@ -123,3 +128,7 @@
123128
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
124129

125130
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
131+
132+
# django-summernote
133+
MEDIA_URL = '/media/'
134+
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

pyconkr/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@
1818

1919
urlpatterns = [
2020
path("api-auth/", include("rest_framework.urls")),
21+
path('summernote/', include("django_summernote.urls")),
2122
path("admin/", admin.site.urls),
23+
path("sponsors/", include("sponsor.urls")),
2224
]

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ Markdown==3.4.1
88
mysql-connector-python==8.0.32
99
mysqlclient==2.1.1
1010
sqlparse==0.4.3
11-
tzdata==2022.7
11+
tzdata==2022.7
12+
sorl-thumbnail==12.9.0

sponsor/__init__.py

Whitespace-only changes.

sponsor/admin.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from django.contrib import admin
2+
from sponsor.models import Sponsor, SponsorLevel
3+
4+
5+
class SponsorAdmin(SummernoteModelAdmin):
6+
formfield_overrides = {models.TextField: {
7+
'widget': SummernoteWidgetWithCustomToolbar}}
8+
autocomplete_fields = ('creator', 'manager_id',)
9+
list_display = ('creator', 'name', 'level', 'manager_name', 'manager_email', 'manager_id',
10+
'submitted', 'accepted', 'paid_at',)
11+
list_filter = ('accepted',)
12+
ordering = ('-created_at',)
13+
14+
15+
admin.site.register(Sponsor, SponsorAdmin)
16+
17+
18+
class SponsorLevelAdmin(SummernoteModelAdmin):
19+
list_display = ('id', 'order', 'name', 'slug', 'price', 'limit',)
20+
list_editable = ('order', 'slug',)
21+
ordering = ('order',)
22+
search_fields = ('name',)
23+
24+
25+
admin.site.register(SponsorLevel, SponsorLevelAdmin)

sponsor/apps.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class SponsorConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "sponsor"

sponsor/models.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
from django.db import models
2+
from django.contrib.auth import get_user_model
3+
from sorl.thumbnail import ImageField as SorlImageField
4+
5+
User = get_user_model()
6+
7+
8+
class SponsorLevelManager(models.Manager):
9+
def get_queryset(self):
10+
return super(SponsorLevelManager, self).get_queryset().all().order_by("order")
11+
12+
13+
class SponsorLevel(models.Model):
14+
name = models.CharField(max_length=255, blank=True, default="", help_text="후원 등급명")
15+
desc = models.TextField(
16+
null=True, blank=True, help_text="후원 혜택을 입력하면 될 거 같아요 :) 후원사가 등급을 정할 때 볼 문구입니다."
17+
)
18+
visible = models.BooleanField(default=True)
19+
price = models.IntegerField(default=0)
20+
limit = models.IntegerField(default=0, help_text="후원사 등급 별 구좌수")
21+
order = models.IntegerField(default=1)
22+
created_at = models.DateTimeField(auto_now_add=True)
23+
updated_at = models.DateTimeField(auto_now=True)
24+
25+
objects = SponsorLevelManager()
26+
27+
@property
28+
def current_remaining_number(self):
29+
return (
30+
0
31+
if self.limit - self.accepted_count < 0
32+
else self.limit - self.accepted_count
33+
)
34+
35+
@property
36+
def paid_count(self):
37+
return Sponsor.objects.filter(
38+
level=self, submitted=True, accepted=True, paid_at__isnull=False
39+
).count()
40+
41+
@property
42+
def accepted_count(self):
43+
return Sponsor.objects.filter(level=self, submitted=True, accepted=True).count()
44+
45+
def __str__(self):
46+
return self.name
47+
48+
49+
def registration_file_upload_to(instance, filename):
50+
return f"sponsor/business_registration/{instance.id}/{filename}"
51+
52+
53+
def logo_image_upload_to(instance, filename):
54+
return f"sponsor/logo/{instance.id}/{filename}"
55+
56+
57+
class Sponsor(models.Model):
58+
class Meta:
59+
ordering = ["paid_at", "id"]
60+
61+
creator = models.ForeignKey(
62+
User,
63+
null=True, # TODO: 추루 로그인 적용 후 입력
64+
blank=True, # TODO: 추루 로그인 적용 후 입력
65+
on_delete=models.CASCADE,
66+
help_text="후원사를 등록한 유저",
67+
related_name="sponsor_creator",
68+
)
69+
name = models.CharField(
70+
max_length=255, help_text="후원사의 이름입니다. 서비스나 회사 이름이 될 수 있습니다."
71+
)
72+
level = models.ForeignKey(
73+
SponsorLevel,
74+
null=True,
75+
on_delete=models.SET_NULL,
76+
blank=True,
77+
help_text="후원을 원하시는 등급을 선택해주십시오. 모두 판매된 등급은 선택할 수 없습니다.",
78+
)
79+
desc = models.TextField(
80+
null=True, blank=True, help_text="후원사 설명입니다. 이 설명은 국문 홈페이지에 게시됩니다."
81+
)
82+
eng_desc = models.TextField(
83+
null=True, blank=True, help_text="후원사 영문 설명입니다. 이 설명은 영문 홈페이지에 게시됩니다."
84+
)
85+
manager_name = models.CharField(
86+
max_length=100, help_text="준비위원회와 후원과 관련된 논의를 진행할 담당자의 이름을 입력해주십시오."
87+
)
88+
manager_email = models.CharField(
89+
max_length=100,
90+
help_text="입력하신 메일로 후원과 관련된 안내 메일이나 문의를 보낼 예정입니다. 후원 담당자의 이메일 주소를 입력해주십시오.",
91+
)
92+
manager_id = models.ForeignKey(
93+
User,
94+
null=True,
95+
blank=True,
96+
on_delete=models.CASCADE,
97+
help_text="후원사를 위한 추가 아이디",
98+
related_name="sponsor_temp_id",
99+
)
100+
business_registration_number = models.CharField(
101+
max_length=100,
102+
null=True,
103+
blank=True,
104+
help_text="후원사 사업자 등록번호입니다. 세금 계산서 발급에 사용됩니다.",
105+
)
106+
business_registration_file = models.FileField(
107+
null=True,
108+
blank=True,
109+
upload_to=registration_file_upload_to,
110+
help_text="후원사 사업자 등록증 스캔본입니다. 세금 계산서 발급에 사용됩니다.",
111+
)
112+
url = models.CharField(
113+
max_length=255,
114+
null=True,
115+
blank=True,
116+
help_text="파이콘 홈페이지에 공개되는 후원사 홈페이지 주소입니다.",
117+
)
118+
logo_image = SorlImageField(
119+
upload_to=logo_image_upload_to,
120+
null=True,
121+
blank=True,
122+
help_text="홈페이지에 공개되는 후원사 로고 이미지입니다.",
123+
)
124+
submitted = models.BooleanField(
125+
default=False,
126+
help_text="사용자가 제출했는지 여부를 저장합니다. 요청이 제출되면 준비위원회에서 검토하고 받아들일지를 결정합니다.",
127+
)
128+
accepted = models.BooleanField(
129+
default=False, help_text="후원사 신청이 접수되었고, 입금 대기 상태인 경우 True로 설정됩니다."
130+
)
131+
paid_at = models.DateTimeField(
132+
null=True, blank=True, help_text="후원금이 입금된 일시입니다. 아직 입금되지 않았을 경우 None이 들어갑니다."
133+
)
134+
created_at = models.DateTimeField(auto_now_add=True)
135+
updated_at = models.DateTimeField(auto_now=True)
136+
137+
def __str_(self):
138+
return f"{self.name}/{self.level}"

sponsor/tests.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.test import TestCase
2+
3+
# Create your tests here.

sponsor/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.contrib import admin
2+
from django.urls import path, include
3+
4+
urlpatterns = [
5+
# path("", ), # TODO
6+
]

sponsor/views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.shortcuts import render
2+
3+
# Create your views here.

0 commit comments

Comments
 (0)