[Django]심화 인스타그램 기능 클론

손성수·2023년 4월 20일
0

Django

목록 보기
15/17

Image Field

장고 static 공식 문서

  • static files
    JavaScrpit,CSS,Image 제공

  • static 설정

settings.py
STATIC_URL = "static/"

STATICFILES_DIRS = [
    BASE_DIR / "static",
    "/var/www/static/",
]

---------------------------------------------

app urls.py

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # ... the rest of your URLconf goes here ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
---------------------------------------------


html 설정
{% load static %}
<img src="{% static 'my_app/example.jpg' %}" alt="My image">

장고 이미지 필드 공식문서

  • 이미지필드는 파일필드를 상속받는다
    너비와 높이 지정 가능

Pillow 라이브러리 요구
장고 각 필드에대한 가이드 공식문서

  • 이미지 필드와 파일 필드를 사용학 위해서 설정해야할것
  1. MEDIA_ROOT 설정
  2. MEDIA_URL 설정
  3. 서브디렉토의 경로 설정(업로드)

STATIC/MEDIA URL 설정

settings.py

STATIC_ROOT = BASE_DIR / "static"
STATIC_URL = '/static/'

MEDIA_ROOT = BASE_DIR/ "media"
MEDIA_URL = '/media/'

app.urls.py 설정

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
	....
]


urlpatterns+= static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns+= static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


이미지필드 속성 설정

image = models.ImageField(blank=True, upload_to='%Y/%m/')
  • blacnk 빈 값
  • upload_to 시간

등록될 이미지의 날짜별 관리 가능





게시글 CRUD

class ArticleView(APIView):
    def get(self,request):
        articles = Article.objects.all()
        # serializer = ArticleSerializer(articles,many=True)
        serializer = ArticleListSerializer(articles, many=True)
        return Response(serializer.data,status=status.HTTP_200_OK)

    def post(self,request):
        serializer = ArticleCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user)
            return Response(serializer.data,status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)


class ArticleDetailView(APIView):
    def get(self, request,article_id):
        article = get_object_or_404(Article,id=article_id)
        serializer = ArticleSerializer(article)
        return Response(serializer.data,status=status.HTTP_201_CREATED)

    def put(self, request,article_id):
        article = get_object_or_404(Article, id=article_id)
        if request.user == article.user:
            serializer = ArticleCreateSerializer(article,data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data,status=status.HTTP_200_OK)
            else:
                return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response("권한이 없습니다!",status=status.HTTP_403_FORBIDDEN)

    def delete(self, request,article_id):
        article = get_object_or_404(Article, id=article_id)
        if request.user == article.user:
            article.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            return Response("권한이 없습니다!",status=status.HTTP_403_FORBIDDEN)

  • serializer
class ArticleSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    def get_user(self, obj):
        return obj.user.email

    class Meta:
        model = Article
        fields = "__all__"

class ArticleCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ("title","image","content")


class ArticleListSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    def get_user(self,obj):
        return obj.user.email
    # 약속된 형태, 메소드 필드를 받고, get_user를 사용하여 user의 email 값을 반환받는다.

    class Meta:
        model = Article
        fields = ("pk","title","image","updated_at","user")




댓글 기능

  • 역참조
article = models.ForeignKey(Article, on_delete=models.CASCADE,related_name="comment_set")

related_name="comment_set"을 등록하지 않아도, 기본적으로 사용할 수 있다.
주의사항 : Many To Many 필드에는 항상 related_name을 설정해줘야 한다.

serializer 구축

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = "__all__"

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ("content",)

주의사항 : fields의 튜플에 항상 ,를 붙여줘야 한다.





Like (ManyToMany)

모델 설계

class Article(models.Model):
    user = models.ForeignKey(User,on_delete=models.CASCADE)
    ...
    likes = models.ManyToManyField(User,related_name="like_articles")

user의 역참조
user.article_set : 유저가 작성한 게시글 역참조
user.like_articles : 유저가 좋아요한 게시글 역참조

역참조 이해

class School(models.Model):
	....
class Student(models.Model):
	school = models.ForeignKey(School,on_delete_True)
    ....

related_name, 역참조 이름을 설정하지 않으면
School에서 Student를 역참조 하기 위해서는
school(오브젝트).school_set.all()
이러한 방법으로 역참조한 데이터를 모두 가져올 수 있으며

class Student(models.Model):
	school = models.ForeignKey(School,on_delete_True,related_name="sparta")
    ....

위와 같이 related_name을 sparta로 지정시 역참조하기 위해
school(오브젝트).sparta.all()
이러한 방법으로 역참조 데이터를 가져올 수 있다.

  • 좋아요 CBV
class LikeView(APIView):
    def post(self,request,article_id):
        article = get_object_or_404(Article,id=article_id)
        if request.user in article.likes.all():
            article.likes.remove(request.user)
            return Response("좋아요", status=status.HTTP_200_OK)
        else:
            article.likes.add(request.user)
            return Response("좋아요 취소", status=status.HTTP_200_OK)

좋아요 기능은 팔로우 기능과 굉장히 흡사하다.

  • Follow
class FollowView(APIView):
    def post(self,request,user_id):
        click_user = get_object_or_404(User,id=user_id)
        if request.user in click_user.followers.all():
            click_user.followers.remove(request.user)
            return Response("unfollow", status=status.HTTP_200_OK)
        else:
            click_user.followers.add(request.user)
            return Response("follow", status=status.HTTP_200_OK)

Many - to - Many 설계

followings = models.ManyToManyField('self',symmetrical=False,related_name='followers')

symmetrical=False : 상호 관계성에 일방적으로 등록이 가능
many-to-many field는 항시 related_name을 설정해야한다.





디테일 페이지 수정

serializers.py

class ArticleSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    comment_set = CommentSerializer(many=True)
    def get_user(self, obj):
        return obj.user.email
        
    class Meta:
        model = Article
        fields = "__all__"

상세페이지 Serializer 모델에 댓글 내역을
역참조를 통해 추가

댓글 내역은 성공적으로 가져왔으며 likes에는
like를 누른 유저의 id값이 출력되고 있다.
프론트에서는 이 id값으로 출력되는것이 데이터를 가공 하는데 있어 조금더 편하겠지만
이 정보를 이메일로 바꿔보자.

DRF Serializer relations 공식문서

class ArticleSerializer(serializers.ModelSerializer):
	...
    likes = serializers.StringRelatedField(many=True)
    ...

StringRelatedField추가

User Model의 pk값을 str값으로 변환하여 반환한다.





게시글 리스트

  • 게시글 리스트에 댓글,좋아요 개수 가져오기
class ArticleListSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    likes_count = serializers.SerializerMethodField()
    comments_count = serializers.SerializerMethodField()

    def get_user(self,obj):
        return obj.user.email
    # 약속된 형태, 메소드 필드를 받고, get_user를 사용하여 user의 email 값을 반환받는다.
    def get_likes_count(self,obj):
        return obj.likes.count()
    def get_comments_count(self,obj):
        return obj.comment_set.count()


    class Meta:
        model = Article
        fields = ("pk","title","image","updated_at","user","likes_count","comments_count")

MethodField : 직렬변환(JSON변환)데이터 추가

obj.object.count() (총 개수 반환)

comment_set의경우, comment모델을 역참조하여 데이터를 가져온다.





프로필 페이지 추가

views.py

class ProfileView(APIView):
    def get(self,request,user_id):
        user = get_object_or_404(User,id=user_id)
        serializer = UserProfileSerializer(user)
        return Response(serializer.data)

serializers.py

class UserProfileSerializer(serializers.ModelSerializer):
    followers = serializers.StringRelatedField(many=True)
    followings = serializers.StringRelatedField(many=True)
    article_set = ArticleListSerializer(many=True)
    like_articles = ArticleListSerializer(many=True)

    class Meta:
        model = User
        fields = ("id","email","followings","followers","article_set","like_articles")




feed 페이지 추가

q 공식문서

class FeedView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    def get(self,request):
        q = Q()
        for user in request.user.followings.all():
            q.add(Q(user=user),q.OR)
        feeds = Article.objects.filter(q)
        serializer = ArticleSerializer(feeds,many=True)
        return Response(serializer.data)
profile
더 노력하겠습니다

0개의 댓글

관련 채용 정보