diff --git a/README.md b/README.md index 0ad0c35..77c2ff0 100644 --- a/README.md +++ b/README.md @@ -19,5 +19,12 @@ work in progress: ![django](https://img.shields.io/badge/Django-092E20?style=for-the-badge&logo=django&logoColor=white) -# 9주차 스탠다드 과제 -![](https://github.com/LikeLion-at-CAU-12th/kangRok-Lee/assets/34326056/64c47b02-4a0a-4946-82e4-b7ab70602d85) \ No newline at end of file +# 10주차 스탠다드 과제 +1. 이미지 확장자를 png는 제한하고, png 파일이 입력으로 들어왔을 때 지정한 에러로 처리하기 +원래 serializers.py로 거르려다가, 로직은 views.py에 있어야한다는 내용을 어디선가 보고 views.py에 만들었습니다 +![](https://github.com/LikeLion-at-CAU-12th/kangRok-Lee/assets/34326056/20011650-d00a-477d-84d7-e164f9f50cec) +2. DB에 이미지 파일 이름이 아닌, S3 버킷 내 url로 저장될 수 있도록 하기 +아래처럼 전체 url이 DB에 저장됩니다 +![](https://github.com/LikeLion-at-CAU-12th/kangRok-Lee/assets/34326056/9a62629e-d8cf-4476-88d6-191e68b7785b) + +기말 파이팅하세용 \ No newline at end of file diff --git a/config/settings.py b/config/settings.py index c1f4324..b81d0d6 100644 --- a/config/settings.py +++ b/config/settings.py @@ -72,6 +72,7 @@ def get_secret(setting, secrets=secrets): "allauth.account", "allauth.socialaccount", "allauth.socialaccount.providers.google", + 'storages', ] @@ -122,14 +123,23 @@ def get_secret(setting, secrets=secrets): # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases +# DATABASES = { +# 'default': { +# 'ENGINE': 'django.db.backends.sqlite3', +# 'NAME': BASE_DIR / 'db.sqlite3', +# } +# } DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', - } + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': get_secret("DB_NAME"), + 'USER': 'admin', # root로 접속하여 DB를 만들었다면 'root' + 'PASSWORD': get_secret("DB_PASSWORD"), + 'HOST': get_secret("DB_HOST"), + 'PORT': '3306' # default mysql portnumber + } } - # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators @@ -209,4 +219,18 @@ def get_secret(setting, secrets=secrets): ACCOUNT_EMAIL_REQUIRED = True # email 필드 사용 o ACCOUNT_USERNAME_REQUIRED = True # username 필드 사용 o -ACCOUNT_AUTHENTICATION_METHOD = "email" \ No newline at end of file +ACCOUNT_AUTHENTICATION_METHOD = "email" + +###AWS### +AWS_ACCESS_KEY_ID = get_secret("AWS_ACCESS_KEY_ID") # .csv 파일에 있는 내용을 입력 Access key ID +AWS_SECRET_ACCESS_KEY = get_secret("AWS_SECRET_ACCESS_KEY") # .csv 파일에 있는 내용을 입력 Secret access key +AWS_REGION = 'ap-northeast-2' + +###S3### +AWS_STORAGE_BUCKET_NAME = 'qwertycvbnm' +AWS_S3_CUSTOM_DOMAIN = '%s.s3.%s.amazonaws.com' % (AWS_STORAGE_BUCKET_NAME,AWS_REGION) +AWS_S3_OBJECT_PARAMETERS = { + 'CacheControl': 'max-age=86400', +} + +DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' # 장고의 기본 파일저장소 위치를 S3버킷으로 지정. \ No newline at end of file diff --git a/posts/migrations/0009_post_thumbnail.py b/posts/migrations/0009_post_thumbnail.py new file mode 100644 index 0000000..05184e9 --- /dev/null +++ b/posts/migrations/0009_post_thumbnail.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.4 on 2024-06-05 15:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('posts', '0008_remove_post_image'), + ] + + operations = [ + migrations.AddField( + model_name='post', + name='thumbnail', + field=models.ImageField(blank=True, null=True, upload_to='', verbose_name='썸네일'), + ), + ] diff --git a/posts/models.py b/posts/models.py index 11ebb23..81a441d 100644 --- a/posts/models.py +++ b/posts/models.py @@ -1,5 +1,6 @@ from django.db import models from config.settings import AUTH_USER_MODEL +from django.core.files.storage import default_storage # Create your models here. class BaseModel(models.Model) : @@ -24,6 +25,30 @@ class Post(BaseModel) : content = models.TextField(verbose_name="내용") category = models.CharField(choices=CHOICES, max_length=20) # image = models.ImageField(verbose_name="사진 첨부", upload_to='images/', null=True, blank=True) + thumbnail = models.ImageField(null=True, blank=True, verbose_name="썸네일") + + def save(self, *args, **kwargs): + file = self.thumbnail + if file: + self.thumbnail = default_storage.url(file.name) #default_storage points to our S3 + super().save(*args, **kwargs) + + """ + TODO: fix + response에서 + "https://qwertycvbnm.s3.ap-northeast-2.amazonaws.com/https%3A/qwertycvbnm.s3.ap-northeast-2.amazonaws.com/quokka.webp" + 와 같이 default.storage 값이 두번 중복되어 옴 + """ + + """ + ++DB에 URL 저장하지 않고 썸네일 전체URL 사용하기 + @property + def thumbnail_url(self): + if self.thumbnail and hasattr(self.thumbnail, 'url'): + return self.thumbnail.url + else: + return None + """ class Comment(BaseModel) : id = models.AutoField(primary_key=True) diff --git a/posts/views.py b/posts/views.py index 2b9bbbd..dd02717 100644 --- a/posts/views.py +++ b/posts/views.py @@ -14,6 +14,7 @@ from django.http import Http404 from rest_framework.permissions import IsAuthenticated from accounts.permissions import KeyHeaderPermission, IsPostAuthor +import os def hello_world(request): if request.method == "GET": @@ -59,6 +60,16 @@ def get_permissions(self): self.permission_classes = [KeyHeaderPermission, IsAuthenticated] return super(PostListAPIView, self).get_permissions() + # @Override + def create(self, request, *args, **kwargs): + thumbnail = request.data.get('thumbnail') + if thumbnail: + ext = os.path.splitext(thumbnail.name)[1] + if ext.lower() == ".png": + return Response(".png extensions not allowed", status=status.HTTP_400_BAD_REQUEST) + return super(PostListAPIView, self).create(request, *args, **kwargs) + + class PostDetailAPIView(generics.RetrieveUpdateDestroyAPIView): permission_classes = [KeyHeaderPermission, IsPostAuthor, IsAuthenticated] queryset = Post.objects.all() diff --git a/requirements.txt b/requirements.txt index 9ec8080..f6b8e19 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,33 @@ asgiref==3.8.1 +boto3==1.34.119 +botocore==1.34.119 +certifi==2024.6.2 +cffi==1.16.0 +charset-normalizer==3.3.2 +cryptography==42.0.8 Django==5.0.4 +django-allauth==0.63.3 django-cors-headers==4.3.1 +django-storages==1.14.3 djangorestframework==3.15.1 djangorestframework-simplejwt==5.3.1 drf-yasg==1.21.7 +idna==3.7 inflection==0.5.1 +jmespath==1.0.1 +mysqlclient==2.2.4 packaging==24.0 +pillow==10.3.0 +pycparser==2.22 PyJWT==2.8.0 +python-dateutil==2.9.0.post0 pytz==2024.1 PyYAML==6.0.1 +requests==2.32.3 +s3transfer==0.10.1 +setuptools==70.0.0 +six==1.16.0 sqlparse==0.5.0 typing_extensions==4.11.0 uritemplate==4.1.1 +urllib3==2.2.1