From 97a2ba811aaa70e252a5b17b59992677d02751c1 Mon Sep 17 00:00:00 2001 From: kmh0601 Date: Sun, 9 Jun 2024 01:30:04 +0900 Subject: [PATCH] feat: 10th standard --- README.md | 13 +++++- session_3/config/S3ImageUploader.py | 18 ++++++++ session_3/config/settings.py | 43 +++++++++++++++---- .../posts/migrations/0006_post_thumbnail.py | 18 ++++++++ session_3/posts/models.py | 2 + session_3/posts/serializers.py | 9 +++- session_3/posts/views.py | 17 +++++++- session_3/requirements.txt | 16 +++++++ 8 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 session_3/config/S3ImageUploader.py create mode 100644 session_3/posts/migrations/0006_post_thumbnail.py diff --git a/README.md b/README.md index f24ed32..e79e27c 100644 --- a/README.md +++ b/README.md @@ -87,10 +87,21 @@ +
+9주차 +
## 9주차 스탠다드 과제 캡쳐본 ### 1-1.social user로 등록되지 않은 gmail로 로그인 ![과제 1-1](https://i.postimg.cc/RZm6rdcq/image.png) ### 1-2.social user로 등록된 gmail로 로그인 -![과제 1-2](https://i.postimg.cc/wTgggGGK/image.png) \ No newline at end of file +![과제 1-2](https://i.postimg.cc/wTgggGGK/image.png) +
+
+ +## 10주차 스탠다드 과제 캡쳐본 +### 1-1. png 저장시 에러 +![과제 1-1](https://i.postimg.cc/GtHPWtRy/image.png) +### 1-2. db에 url 저장 +![과제 1-2](https://i.postimg.cc/L6pRHbhn/image.png) diff --git a/session_3/config/S3ImageUploader.py b/session_3/config/S3ImageUploader.py new file mode 100644 index 0000000..c363ef3 --- /dev/null +++ b/session_3/config/S3ImageUploader.py @@ -0,0 +1,18 @@ +from config import settings +import boto3 +import uuid + +class S3ImageUploader: + def __init__(self, file): + self.file = file + + def upload(self): + s3_client = boto3.client( + 's3', + aws_access_key_id=settings.AWS_ACCESS_KEY_ID, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + region_name=settings.AWS_REGION + ) + i = str(uuid.uuid4()) + response = s3_client.upload_fileobj(self.file, settings.AWS_STORAGE_BUCKET_NAME, i) + return f'https://{settings.AWS_STORAGE_BUCKET_NAME}.s3.{settings.AWS_REGION}.amazonaws.com/{i}' \ No newline at end of file diff --git a/session_3/config/settings.py b/session_3/config/settings.py index e58a7f4..3f77757 100644 --- a/session_3/config/settings.py +++ b/session_3/config/settings.py @@ -14,8 +14,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent # Media -MEDIA_ROOT = BASE_DIR / 'media' # 사용자가 업로든한 파일들이 실제로 저장되는 경로 -MEDIA_URL = '/media/' # 미디어를 처리하는 URL +# MEDIA_ROOT = BASE_DIR / 'media' # 사용자가 업로든한 파일들이 실제로 저장되는 경로 +# MEDIA_URL = '/media/' # 미디어를 처리하는 URL # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -62,7 +62,8 @@ def get_secret(setting, secrets=secrets): "allauth", "allauth.account", "allauth.socialaccount", - "allauth.socialaccount.providers.google", + "allauth.socialaccount.providers.google", + "storages", ] @@ -118,11 +119,22 @@ def get_secret(setting, secrets=secrets): # Database # https://docs.djangoproject.com/en/4.2/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 + } } @@ -183,4 +195,19 @@ def get_secret(setting, secrets=secrets): 'ROTATE_REFRESH_TOKENS': False, 'BLACKLIST_AFTER_ROTATION': False, 'TOKEN_USER_CLASS': 'accounts.User', # 토큰에 사용할 Model -} \ No newline at end of file +} + + +###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 = 'kmhbucket' +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/session_3/posts/migrations/0006_post_thumbnail.py b/session_3/posts/migrations/0006_post_thumbnail.py new file mode 100644 index 0000000..3f9d452 --- /dev/null +++ b/session_3/posts/migrations/0006_post_thumbnail.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.11 on 2024-06-09 00:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('posts', '0005_alter_post_user'), + ] + + operations = [ + migrations.AddField( + model_name='post', + name='thumbnail', + field=models.ImageField(blank=True, null=True, upload_to='', verbose_name='썸네일'), + ), + ] diff --git a/session_3/posts/models.py b/session_3/posts/models.py index 24baf28..ba71c86 100644 --- a/session_3/posts/models.py +++ b/session_3/posts/models.py @@ -31,6 +31,8 @@ class Post(BaseModel): content = models.TextField(verbose_name='내용') writer = models.CharField(verbose_name='작성자', max_length=10) category = models.CharField(choices=CHOICES, max_length=20) + #10th session s3때문에 추가함~ + thumbnail = models.ImageField(null=True, blank=True, verbose_name="썸네일") ''' id PK int diff --git a/session_3/posts/serializers.py b/session_3/posts/serializers.py index a011cdd..93d56e3 100644 --- a/session_3/posts/serializers.py +++ b/session_3/posts/serializers.py @@ -3,17 +3,24 @@ from .models import Comment from django.core.exceptions import ValidationError + class PostSerializer(serializers.ModelSerializer): class Meta: model = Post fields = "__all__" - # # 원하는 필드만 가져올 수 있음 # fileds = ['writer','content'] # # 원하지 않는 필드를 지정할 수 있음 # exclude = ['category'] # # 수정 불가능 옵션으로 필드를 가져올 수 있음 + + def validate(self, data): + thumbnail = data.get("thumbnail") + if thumbnail.content_type.split("/")[-1] == "png": + raise serializers.ValidationError("thumbnail can not be .png") + return data + class CommentSerializer(serializers.ModelSerializer): class Meta: diff --git a/session_3/posts/views.py b/session_3/posts/views.py index bbf3e3f..3c4efc1 100644 --- a/session_3/posts/views.py +++ b/session_3/posts/views.py @@ -283,7 +283,7 @@ def post(self, request, format=None): data = request.data data['user'] = request.user.id serializer = PostSerializer(data=data) - if serializer.is_valid(): + if serializer.is_valid(data): serializer.save(); return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_404_NOT_FOUND) @@ -315,9 +315,24 @@ def get(self, request, id): # post = get_object_or_404(Post, id=id) # post.delete() # return Response(status=status.HTTP_204_NO_CONTENT) + +from config import S3ImageUploader + class PostList(generics.ListCreateAPIView): queryset = Post.objects.all() serializer_class = PostSerializer + + def post(self, request, format=None): + data = request.data + print(data) + serializer = PostSerializer(data=data) + if serializer.is_valid(): + image = request.FILES["thumbnail"] + url = S3ImageUploader.S3ImageUploader(image).upload() + serializer.save(thumbnail = url); + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_404_NOT_FOUND) + class PostDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Post.objects.all() serializer_class = PostSerializer diff --git a/session_3/requirements.txt b/session_3/requirements.txt index 36a97d6..71506ad 100644 --- a/session_3/requirements.txt +++ b/session_3/requirements.txt @@ -1,13 +1,29 @@ asgiref==3.7.2 +boto3==1.34.119 +botocore==1.34.119 +certifi==2024.2.2 +charset-normalizer==3.3.2 Django==4.2.11 +django-allauth==0.63.2 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.1.1 packaging==24.0 pillow==10.3.0 +PyJWT==2.8.0 +python-dateutil==2.9.0.post0 pytz==2024.1 PyYAML==6.0.1 +requests==2.32.2 +s3transfer==0.10.1 +six==1.16.0 sqlparse==0.4.4 typing_extensions==4.10.0 uritemplate==4.1.1 +urllib3==1.26.18