본문 바로가기

회고록(TIL&WIL)

TIL 2022.07.12 DRF TestCode2, DRF 라이브코딩 소스코드

from django.urls import reverse
from rest_framework.test import APITestCase
from .models import User

# Create your tests here.

# 이미지업로드(임시 파일을 만들어 가상 이미지 생성)
from django.test.client import MULTIPART_CONTENT, encode_multipart, BOUNDARY
from PIL import Image
import tempfile # 임시파일을 만드는 라이브러리

def get_temporary_image(temp_file):
    size = (200, 200)
    color = (255, 0, 0)
    image = Image.new("RGBA", size, color)
    image.save(temp_file, 'png')
    return temp_file
    

class ArticleCreateTest(APITestCase):
    # 테스트를 시작할 때 모든 메서드에 대해서 아래 함수 실행됨
    @classmethod
    def setUpTestData(cls):
        cls.user_data = {"email": "ggg@ggg.com","fullname": "GGG", "password": "ggg"}
        cls.article_data = {"title": "some title", "content": "some content"}
        cls.user = User.objects.create_user('ggg@ggg.com', 'ggg')
    
    
    def setUp(self):
        self.access_token = self.client.post(reverse('token_obtain_pair'), self.user_data).data['access']
    
    # 테스트 함수 명은 반드시 맨앞에 test_ 가 붙어있어야한다!
    # 로그인이 되어있지 않은 유저가 게시글 작성 시도 시 401
    def test_fail_if_not_logged_in(self):
        url = reverse("article_view")
        response = self.client.post(url, self.article_data)
        self.assertEqual(response.status_code, 401)
            
    # 글작성 테스트(이미지 없음)
    def test_create_article(self):
        response = self.client.post(
            path=reverse("article_view"),
            data=self.article_data,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}"
        )
        self.assertEqual(response.data["message"], "글 작성 완료!")
        self.assertEqual(response.status_code, 200)
        
    # 글작성 테스트(이미지 포함)
    def test_create_article_with_image(self):
        # 임시 이미지 파일 생성
        temp_file = tempfile.NamedTemporaryFile() # 이름이있는 그냥 빈파일 생성
        temp_file.name = "image.png"  # 이름 지정
        image_file = get_temporary_image(temp_file) # 빈파일을 아까 만들어둔 함수에 인자로 줘서 이미지 파일로 생성
        image_file.seek(0) # 첫번째 프레임을 가져와야함
        
        # 생성한 이미지 파일을 article_data에 추가
        self.article_data["image"] = image_file
        
        # 전송
        response = self.client.post(
            path=reverse("article_view"),
            data=encode_multipart(data=self.article_data, boundary=BOUNDARY),
            content_type=MULTIPART_CONTENT,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}"
        )
        self.assertEqual(response.data["message"], "글 작성 완료!")
        self.assertEqual(response.status_code, 200)

python manage.py test (app이름)  app 이름을 입력할 경우 해당 앱의 tests.py 만 실행됨

test 함수를 작성할 떄 함수명을 반드시 test_ 로 시작해야 test를 돌릴 수 있다.

 


단축키 강의
ctrl + alt 멀티커서
alt 클릭 
ctrl + f2 같은 단어 드래그
한줄 복사 copy line down
라인에서 ctrl + shift 위아래
라인에서 ctrl + x 한줄 지우기
ctrl + shift + n 파일검색
ctrl + shift + f 단어검색
ctrl K S 눌리면 단축키 변경 가능

폴더 깡통 만든 후
python -m venv venv
pip install django
pip install djangorestframework

pip freeze > requirements.txt
django-damin startproject shopping .
python manage.py startapp user
python manage.py startapp product

#shopping/settings.py
INSTALLED_APP
'rest_framework',
'user',
'product'

STATIC_URL = "static/"
MEDIA_URL = "media/"
ABSTRACT_USER = "user.User"
#user/models.py
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser

class UserManager(BaseUserManager):
    def create_user(self, username, password=None):
        if not username:
            raise ValueError('Users must have an username')
        user = self.model(
            username=username,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
    
    # python manage.py createsuperuser 사용 시 해당 함수가 사용됨
    def create_superuser(self, username, password=None):
        user = self.create_user(
            username=username,
            password=password
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):
    username = models.CharField(unique=True)
    password = models.CharField
    email = models.EmailField(unique=True)
    fullname = models.CharField
    phone = models.CharField

    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    cart = models.ManyToManyField("product.ProductOption", through="Cart", related_name="carts")
    like = models.ManyToManyField("product.Product", reladted_name="likes")

    USERNAME_FIELD = 'username'
    REQUIRED_FIELD = []
    
    objects = UserManager()

    def __str__(self):
        return self.username

    def has_perm(self, perm, obj=None):
       return True

    def has_module_perms(self, perm, obj=None):
        return True

    @property
    def is_staff(self):
        return self.is_admin

class Celler(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="users")
    approval_date = models.DateTimeField(null=True)

class Cart(models.Model):
    user = ForeignKey(User, on_delete=models.CASCADE)
    count = models.IntegerField
    product_option = models.ForeignKey("product.ProductOption", on_delete=models.CASCADE)

class PurchaseList(models.Model):
    STATUS = (
          ("ready", "배송준비"), ("delivery", "배송중"), ("Done", "배송완료")
     )
    user = ForeignKey(User, on_delete=models.CASCADE)
    count = models.IntegerField
    status = models.CharField(choices=STATUS)

class PurchaseHistory(models.Model):
    STATUS = (
          ("card", "카드"), ("cash", "현금"),
     )
    puerchase_list = models.ManyToManyField(PurchaseList)
    payment_type = models.CharField(choices=STATUS)
    payment_datetime = models.DataTimeField
#product/models.py

class Category(models.Model):
    name = models.CharField
    def __str__(self):
        return self.name

class Product(models.Model):
    user = models.ForeignKey("user.user", on_delete=models.CASCADE)
    thumnail = models.FileField("", upload_to="product/thumnail")
    detail = models.FileField("", upload_to="product/detail")
    category = models.ForeignKey(Category, on_delete=models.SET_NULL)
    title = models.CharField
    discription = models.TextField
    created = modesl.DateTimeField(auto_now_add=True)
    def __str__(self):
        return self.name

class productOption(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    name = CharField
    price = models.IntegerField
    def __str__(self):
        return f"{self.product}의 옵션{self.user.username}님이 등록하신 상품"

class Review(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    user = models.ForeignKey("user.user", on_delete=models.CASCADE)
    rating = modesl.IntegerField
    content = models.CharField
    created = models.DateTimeField
# shopping/urls.py
from django.urls import path, include

path('user/', include('user.urls'),
path('product/', include('product.urls'),
#user/urls.py

path('', views.UserView.as_view())
path('cart/', views.UserCartView.as_view())
#user/views.py

from rest_framework.views import APIView
from rest_framework.response imprt Response
from rest_framework import permissions, status

from user.serializers import UserSerializer

class UserView(APIView):
   def ger(self, request):
        return Response
   # 회원가입
   def post(self, request):
        user_serializer = UserSerializer(data=request.data)
        user_serializer.is_valid(raise_exception=True)
        user_serializer.save()
        return Response(user_serializer.data, status=status.HTTP_200_OK)

   # 회원수정
   def put(self, request):
        return Response
   
   # 회원탈퇴
   def delete(self, request):
        return Response

class UserAPIView(APIView):
    # 로그인
    def post(self, request):
    user = authenticate(request, **request.data)
    if not user:
        login(request, user)
        return Response("error" : "로그인 실패" , status=status.HTTP_400_BAD_REQUEST)
    return Response("message": "로그인 성공", status=stauts.HTTP_200_OK)

    #로그아웃
   def delete(self, request):
        logout(request)
        return Response("message": "로그아웃 완료", status=stauts.HTTP_200_OK)


class UserCartView(APIView):
    def get(self, request):
        carts = CartModel.objects.filter(user=reqeust.user)
        return Response(UserCartSerializer(carts, many=True).data, status=status.HTTP_200_OK)
    
    def post(self, request):
        request.data["user"] = request.user.id
        user_cart_serializer = UserCartSerializer(data=request.data)
        user_cart_serializer.is_valid(raise_exception=True)
        user_cart_serializer.save()
        return Response({})
# user/serializer.py

from rest_framework import serialzers
*User모델들 임포트 해오기

class UserSerializer(serializers.ModelSerializer):
     def create(self, validated_data):
           password = validated_data.pop("password", "")
           user = UserModel(**validated_data)
           user.set_password(password)
           user.save()
    class Meta:
        model = UserModel
        fields = ["username", "email", "password",
                   "fullname", "phone", "cart", "like", ]
        read_only_fields = ["like", "cart", ]
        extra_kwargs = {
                  "password": {"write_only": True}
        }

        


class UserCartSerializer(seserializers.ModelSerializer):
     product_option_id = serializers.IntegerField(write_only=True)     

     product_info = serializer.SerializerMethodField(read_only=True)
     def get_product_info(self, obj):
        return obj.product_option.product.title

     product_option_info = serializers.SerializerMehtodField(read_only=True)
     def get_product_option_info(self, obj):
        return obj.product_option.name

     price = serializers.SerializerMehtodField(read_only=True)
     def get_price(self, obj):
         return obj.product_option.price

    sum_price = serializers.SerializerMehtodField(read_only=True)
     def get_sum_price(self, obj):
         return obj.product_option.price * obj.count
 
     class Meta:
        model = CartModel
        fields = ["user", "count", "product_option_id", "product_info", "product_option_info"]

        extra_kwargs = {
            "user": {"write_only": True}
         }
# user/admin.py

admin.site.register(User)
# product/urls.py

path('', views.ProductView.as_view()),
path('detail/<product_id>', views.ProductDetailView.as_view()),
path('review/update/<product_id>', views.ReviewView.as_view()),
path('review/<product_id>', views.ReviewView.as_view()),
path('<product_id>', views.ProductView.as_view()),
# product/views.py

from rest_framework.views import APIView
from rest_framework.response imprt Response
from rest_framework import permissions, status

from user.serializers import ProductSerializer

class ProductView(APIView):
   # 상품 목록 조회
   def get(self, request):
        return Response(ProductSerializer(ProductModel.objects.all(), many=True), status=status.HTTP_200_OK)

   # 상품 등록
   def post(self, request):
        request.data["user"] = request.user.id

        product_serializer = ProductSerializer(data=request.data)
        product_serializer.is.valid(raise_exception=True)
        product_serializer.save()
        return Response(product_serializer.data, status=status.HTTP_200_OK)

   # 상품 수정 
   def put(self, request):
        try:
            product = ProductModel.objects.get(id=product_id)
        except ProductModel.DoesNotExist:
            return Response({"error" : "없는 상품 입니다."},
                                    status=status.HTTP_400_BAD_REQUEST)
        request.data["user"] = request.user.id

        product_serializer = ProductSerializer(product, data=request.data, partial=True)
        product_serializer.is_valid(raise_exception=True)
        product_serializer.save()
        return Response(product_serializer, status=status.HTTP_200_OK)
   

   def delete(self, request):
        return Response

class ReviewView(APIView):
     def post(self, request):
        request.data["user"] = request.user.id

        review_serializer = ReviewSerializer(data=request.data)
        review_serializer.is.valid(raise_exception=True)
        review_serializer.save()
        return Response(review_serializer, status=status.HTTP_200_OK)

     def put(self, request):
        try:
            review = ReviewModel.objects.get(id=review_id)
        except ReviewModel.DoesNotExist:
            return Response({"error" : "없는 리뷰 입니다."},
                                    status=status.HTTP_400_BAD_REQUEST)
        request.data["user"] = request.user.id

        review_serializer = ReviewSerializer(review, data=request.data, partial=True)
        review_serializer.is.valid(raise_exception=True)
        review_serializer.save()
        return Response(review_serializer, status=status.HTTP_200_OK)


     def delete(self, request):
         return Response({})


class ProductDetailView(APIView):
     def get(self, request, product_id):
        try:
            product = ProductModel.objects.get(id=product_id)
        except ProductModel.DoesNotExist:
            return Response({"error" : "없는 상품 입니다."},
                                    status=status.HTTP_400_BAD_REQUEST)
        response Response({ProductSerializer(product).data, status=status.HTTP_200_OK})
# product/serializer.py

from rest_framework import serialzers
#Product모델들 임포트 해오기

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = CategoryModel
        fields = ["name"]


class ProductSerializer(serializers.ModelSerializer):
    category = serializers.SerializerMethodField()
    def get_category(self, obj):
         return obj.category.name
    class Meta:
        model = UserModel
        fields = ["user", "thumnail", "detail", "title",
                   "category", "discription", "created" ]
        read_only_fields = ["category", "created", ]

        def create(self, validated_data):
           password = validated_data.pop("password", "")
           user = UserModel(**validated_data)
           user.set_password(password)
           user.save()

class ReviewSerializer(serializers.ModelSerializer):
    class Meta:
        model = ReviewModel
        fields = "__all__"
        extra_kwargs= {
             "product": {"write_only": Ture},
        }

class ProductOptionSerializer(serializers.ModelSerializer):
    class Meta:
        medel = ProductOptionModel
        fields = ["name", "price"]


class ProductDetailSerializer(serializers.ModelSerializer):
    category = serializers.SerializerMethodField()
    def get_category(self, obj):
         return obj.category.name

    options = ProductOptionSerializer(many=True, source="productoption_set"
    reiview = ReviewSerializer(many=Ture, source="review_set")
    class Meta:
        model = ProductModel
        fields = "__all__"

라이브코딩하시는 걸 따라 치는 거다보니 누락된 부분도 있고하다 전체적으로 좋은 코드라고 생각하여 참고용으로 저장