내일배움캠프 - DRF 6일차 과제

Dongwoo Kim·2022년 6월 22일
0

내일배움캠프 - DRF

목록 보기
10/12

스파르타코딩클럽

내일배움캠프 AI 웹개발자양성과정 2회차

DRF 강의 6일차 과제

0. 과제내용

  1. product 앱의 product 테이블 구성을 <작성자, 썸네일, 상품 설명, 등록일자, 노출 종료 일자, 가격, 수정 일자, 활성화 여부>로 변경해주세요
  2. django serializer를 사용해 validate / create / update 하는 기능을 구현해주세요
    1. custom validation 기능을 사용해 노출 종료 일자가 현재보다 더 이전 시점이라면 상품을 등록할 수 없도록 해주세요
    2. custom creator 기능을 사용해 상품 설명의 마지막에 "<등록 일자>에 등록된 상품입니다." 라는 문구를 추가해주세요
    3. custom update 기능을 사용해 상품이 update 됐을 때 상품 설명의 가장 첫줄에 "<수정 일자>에 수정되었습니다." 라는 문구를 추가해주세요
  3. product 앱에서 <작성자, 상품, 내용, 평점, 작성일>을 담고 있는 review 테이블을 만들어주세요
  4. review 테이블을 관리자 페이지에서 자유롭게 추가/수정 할 수 있도록 설정해주세요
  5. 현재 날짜를 기준으로, 노출 종료 날짜가 지나지 않았고 활성화 여부가 True이거나 로그인 한 사용자가 등록 한 상품들의 정보를 serializer를 사용해 리턴해주세요
  6. 5번 상품 정보를 리턴 할 때 상품에 달린 review와 평균 점수를 함께 리턴해주세요
    1. 평균 점수는 (리뷰 평점의 합/리뷰 갯수)로 구해주세요
    2. 작성 된 리뷰는 모두 return하는 것이 아닌, 가장 최근 리뷰 1개만 리턴해주세요
  7. 로그인 하지 않은 사용자는 상품 조회만 가능하고, 회원가입 이후 3일 이상 지난 사용자만 상품을 등록 할 수 있도록 권한을 설정해주세요

1. product 앱의 product 테이블 구성을 <작성자, 썸네일, 상품 설명, 등록일자, 노출 종료 일자, 가격, 수정 일자, 활성화 여부>로 변경해주세요

# product/models.py
class Product(models.Model):
    author = models.ForeignKey(UserModel, verbose_name="작성자", on_delete=models.CASCADE)
    title = models.CharField('상품 명', max_length=30)
    content = models.TextField('상품 설명')
    # show_start_at = models.DateTimeField(default="2022-06-20 00:00:00")
    thumbnail = models.ImageField('썸네일', upload_to='product/img', height_field=None, width_field=None, max_length=100)
    price = models.IntegerField('가격', default=0)

    update_at = models.DateTimeField('수정 일자', auto_now=True)
    created_at = models.DateTimeField('등록 일자', auto_now_add=True)
    show_end_at = models.DateTimeField('노출 종료 일자', default="2022-06-25 00:00:00")
    
    is_active = models.BooleanField('활성화 여부', default=True)

    def __str__(self):
        return f'Product : {self.title} - {self.author}'

2. django serializer를 사용해 validate / create / update 하는 기능을 구현해주세요

  1. custom validation 기능을 사용해 노출 종료 일자가 현재보다 더 이전 시점이라면 상품을 등록할 수 없도록 해주세요
  2. custom creator 기능을 사용해 상품 설명의 마지막에 "<등록 일자>에 등록된 상품입니다." 라는 문구를 추가해주세요
  3. custom update 기능을 사용해 상품이 update 됐을 때 상품 설명의 가장 첫줄에 "<수정 일자>에 수정되었습니다." 라는 문구를 추가해주세요
# product/serializers.py
class ProductSerializer(serializers.ModelSerializer):
    author = serializers.SerializerMethodField()
    
    def get_author(self, obj):
        author_name = obj.author.username
        return author_name

    class Meta:
        model = Product
        fields = ["title", "author", "content", "created_at",
                  "show_end_at", 'update_at', 'price', 'is_active']

    def validate(self, data):
        if 'babo' in data.get('title'):
            raise serializers.ValidationError(
                    detail={"error": "부적절한 단어를 사용할 수 없습니다."},
                )
        
        now = timezone.now()
        
        if  data.get('show_end_at') and now > data.get('show_end_at'):
            raise serializers.ValidationError(
                    detail={"error": "노출 종료 일자는 현재보다 과거일 수 없습니다."},
                )

        return data

    def create(self, validated_data):
        author = self.context.get('request').user
        files = self.context.get('request').FILES
        thumbnail = files.get('thumbnail')
        
        product = Product(author=author, thumbnail=thumbnail, 
                          **validated_data)
        product.save()
        
        created_at = product.created_at
        end_msg = f'{created_at.strftime("%Y/%m/%d %H:%M:%S")} 에 등록된 상품입니다.    '

        product.content = product.content + '\n' + end_msg
        product.save()

        return product

    # instance : 수정할 object
    # validated_data : 수정할 내용
    def update(self, instance, validated_data):
        # validated_data = {'username': 'dongwoo', 'email': 'esdx@daum.net', ...}
        for key, value in validated_data.items():
            setattr(instance, key, value)
        instance.save()

        updated_at = instance.update_at
        start_msg = f'{updated_at.strftime("%Y/%m/%d  %H:%M:%S")} 에 수정되었습니다.    ' 
        instance.content = start_msg + '\n' + instance.content
        instance.is_active = True
        instance.save()

        return instance

3. product 앱에서 <작성자, 상품, 내용, 평점, 작성일>을 담고 있는 review 테이블을 만들어주세요

# product/models.py
class Review(models.Model):
    author = models.ForeignKey(UserModel, verbose_name="작성자", on_delete=models.CASCADE)
    product = models.ForeignKey(Product, verbose_name="상품", on_delete=models.CASCADE)
    content = models.TextField('내용', default="")
    rating = models.IntegerField('평점', default=0)
    created_at = models.DateTimeField('작성일', auto_now_add=True)

    def __str__(self):
        return f'Review : {self.product.title} - {self.author.username} ({self.rating})'

4. review 테이블을 관리자 페이지에서 자유롭게 추가/수정 할 수 있도록 설정해주세요

class ProductAdmin(admin.ModelAdmin):
	...
    
admin.site.register(Product, ProductAdmin)
admin.site.register(Review)

5. 현재 날짜를 기준으로, 노출 종료 날짜가 지나지 않았고 활성화 여부가 True이거나 로그인 한 사용자가 등록 한 상품들의 정보를 serializer를 사용해 리턴해주세요

# product/views.py
# 상품 상세 기능
class ProductDetailView(APIView):
    permission_classes = [IsAuthenticatedorRegistedMoreThanThreeDaysUser]
    
    # 상품 상세 보기
    def get(self, request):
        user = request.user             # 현재 로그인한 유저
        show_now_at = timezone.now()    # 현재 시간
        # show_now_at = "2022-06-24 00:00:00"   # 임의 시간

        # 작성자가 현재 로그인한 유저 이거나
        # 현재시간이 노출 시작시간과 종료시간 사이인 제품만 조회
        query = Q(author=user) | ((Q(show_end_at__gte=show_now_at)) & Q(is_active=True))

        # products = Product.objects.all()
        return Response(ProductDetailSerializer(products, many=True).data)

6. 5번 상품 정보를 리턴 할 때 상품에 달린 review와 평균 점수를 함께 리턴해주세요

  1. 평균 점수는 (리뷰 평점의 합/리뷰 갯수)로 구해주세요
  2. 작성 된 리뷰는 모두 return하는 것이 아닌, 가장 최근 리뷰 1개만 리턴해주세요
# product/serializers.py
class ReivewSerializer(serializers.ModelSerializer):
    author = serializers.SerializerMethodField()

    def get_author(self, obj):
        author_name = obj.author.username
        return author_name

    class Meta:
        model = Review
        fields = ["author", "content", "rating", "created_at",]

class ProductDetailSerializer(serializers.ModelSerializer):
    author = serializers.SerializerMethodField()     # 상품 작성자
    avg_rating = serializers.SerializerMethodField() # 평균 review 평점
    review = serializers.SerializerMethodField()     # 가장 최근 review

    def get_author(self, obj):
        author_name = obj.author.username
        return author_name

    def get_review(self, obj):
        reviews = Review.objects.filter(product=obj).order_by("-created_at")
        if 0 < len(reviews):
            return ReivewSerializer(reviews[0]).data
        else:
            return None

    # 평균 review 평점 구하기
    def get_avg_rating(self, obj):
        reviews = Review.objects.filter(product=obj)
        if 0 < len(reviews):
            total_rating = 0
            for review in reviews:
                total_rating += review.rating
            avg_rating = total_rating / len(reviews)
            return avg_rating
        else:
            return None

    class Meta:
        model = Product
        fields = ["title", "author", "content", "created_at",
                  "show_end_at", 'update_at', 'price', 'is_active',
                  "avg_rating", 'review']

7. 로그인 하지 않은 사용자는 상품 조회만 가능하고, 회원가입 이후 3일 이상 지난 사용자만 상품을 등록 할 수 있도록 권한을 설정해주세요

# permissions.py
class IsAuthenticatedorRegistedMoreThanThreeDaysUser(BasePermission):
    """
    get : 비로그인 사용자 가능
    post, put, delete: 로그인 and 가입일 기준 3일 이상 지난 사용자만 가능
    """
    message = '관리자 또는 가입 후 3일 이상 지난 사용자만 게시글을 작성하실 수 있습니다.'

    SAFE_METHODS = ('GET', )

    def has_permission(self, request, view):
        user = request.user

        if user.is_authenticated and user.is_admin:
            return True
            
        if user.is_authenticated and request.user.join_date < (timezone.now() - timedelta(days=3)):
            return True

        if request.method in self.SAFE_METHODS:
            return True
        
        return False

Github

https://github.com/kimphysicsman/nbcamp-drf-2

profile
kimphysicsman

0개의 댓글