Blog project - 2

[ Blog project ]

  • 클래스형 뷰와 함수형 뷰

    • 클래스형 뷰(Class Based View)
      • 자주 처리하는 내용을 미리 구현해 놓은 뷰
      • 제대로 사용하려면 내부 속성 값들을 알고 있어야 함
      • 클래스형 뷰를 사용하여 뷰를 구현해도 최종 실행에서는 함수형 뷰로 변환되어 동작
      • as_view() 메서드를 통해 클래스형 뷰를 함수형 뷰로 변환
    • 함수형 뷰(Function Based View)

      • 함수형 뷰는 request를 기본 매개변수로 가짐
      • URL에 포함된 패턴그룹을 추가 변수로 가짐

        1
        2
        3
        4
        5
        6
        # urls.py
        path('update/<int:pk>/', create_view)

        # views.py
        def create_view(request, pk):
        pass
      • 클래스형 뷰는 자주 처리하는 일들을 묶어둔 반면, 함수형 뷰는 모든 일을 직접 처리해야 함

    • 클래스형 뷰와 함수형 뷰 비교

      • View

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        from django.shortcuts import render
        from django.http import JsonResponse
        from django.views.generic import View

        # 제네릭 뷰를 사용해서 클래스형 뷰를 만들 때는 상속
        # 함수형 뷰처럼 모든 내용을 직접 구현하고 싶을 때는 View를 상속받는다 ex) API View
        class IndexView(View):
        def get(self, *args, **kwargs):
        return render(self.request, 'blog/test.html')

        def indexView(request):
        if request.method == "GET":
        return render(request, 'blog/test.html')


        class JsonView(View):
        def get(self, *args, **kwargs):
        return JsonResponse({"data": 'test'})

        def post(self, *args, **kwargs):
        return JsonResponse({"data": 'test'})

        def jsonView(request):
        if request.method == "GET":
        return JsonResponse({"data": 'test'})
        elif request.method == "POST":
        return JsonResponse({"data": 'test'})
      • CRUDL(Create, Detail, Update, Delete, List View)

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        from django.views.generic.detail import DetailView
        from django.views.generic.list import ListView
        from django.views.generic.edit import CreateView, UpdateView, DeleteView
        from .models import Post
        from django.core.paginator import Paginator
        from django.db.models import Q
        from django.http import Http404
        from django.shortcuts import redirect
        from django.forms import modelform_factory
        from django.shortcuts import get_object_or_404
        from django.urls import reverse_lazy
        from django.shortcuts import reverse

        # ListView CBV
        class PostList(ListView):
        model = Post
        # default : app_name/model_list.html
        template_name = 'blog/post_list.html'
        # 페이징 기능 활성화
        paginate_by = 1 # 한 페이지당 요소 갯수
        page_kwarg = 'p'

        """
        setup()
        dispatch()
        get_queryset()
        get_context_data()
        render_to_response()
        """

        # ListView FBV
        def postList(request, page):
        # 페이지 번호 얻기
        page = page if page else 1
        page = int(page)

        queryset = Post.objects.all() # CBV : get_queryset

        # post으로 전달된 데이터 중에서 search 변수값 찾기
        search_keyword = request.POST.get('search', request.GET.get('search', None))
        context_data = {}
        if search_keyword:
        q = Q(text__icontains=search_keyword)
        q |= Q(title__icontains=search_keyword)
        queryset = queryset.filter(q)
        context_data.update({'search_keyword': search_keyword})

        # 페이징 처리
        paginator = Paginator(queryset, 1)
        page = paginator.page(page)
        context_data.update({'object_list': page.object_list,
        'paginator': paginator, 'page_obj': page, 'is_paginated': True})

        return render(request, 'blog/post_list.html', context_data)


        # DetailView CBV
        class PostDetail(DetailView):
        model = Post
        template_name = 'blog/post_detail.html'

        # pk의 이름을 post_id로 바꾸기
        pk_url_kwarg = 'post_id'
        """
        setup()
        dispatch()
        get()
        get_object() - get_queryset()
        get_context_data()
        render_to_response()
        """

        # DetailView FBV
        def postDetail(request, pk):
        try:
        object = Post.objects.get(pk=pk)
        except:
        raise Http404("Post does not exists")
        return render(request, 'blog/post_detail.html', {'object': object})


        # CreateView CBV
        class PostCreate(CreateView):
        model = Post
        fields = ['category', 'title', 'text']
        # appname/model_form.html
        template_name = 'blog/post_create.html'

        # success_url이 있는 Create, Update, Delete의 경우
        # 클래스의 속성값을 사용해서 URL을 만들 수 있다.
        # success_url = 'pattern/{변수명}/'
        def form_valid(self, form):
        form.instance.author_id = self.request.user.id
        return super().form_valid(form)

        """
        setup()
        dispatch()
        get()
        post() - 저장처리
        get_context_data()
        render_to_response()
        """

        # CreateView FBV
        def postCreate(request):
        # form_factory : 폼을 쉽게 생성하기 위해 사용하는 클래스, Factory 패턴
        # 기존에 Form Class를 별도로 만드는 방식보다 간단하게 폼을 만들어서 처리할 수 있다는 장점이 있다.
        form_class = modelform_factory(Post, fields=['category', 'title', 'text'])
        if request.method == "POST":
        form = form_class(request.POST)
        form.instance.author_id = request.user.id
        if form.is_valid():
        instance = form.save()
        return redirect(instance)
        else:
        form = form_class()

        return render(request, 'blog/post_create.html', {'form': form})


        # UpdateView CBV
        class PostUpdate(UpdateView):
        model = Post
        fields = ['category', 'title', 'text']
        template_name = 'blog/post_update.html'
        """
        setup()
        dispatch()
        get()
        post() - 저장처리
        get_object()
        get_context_data()
        render_to_response()
        """

        # UpdateView FBV
        def postUpdate(request, pk):
        object = get_object_or_404(Post, pk=pk)
        form_class = modelform_factory(Post, fields=['category', 'title', 'text'])

        if request.method == "POST":
        # 수정시에는 instance 필히 지정
        form = form_class(request.POST, instance=object)
        if form.is_valid():
        instance = form.save()
        return redirect(instance)
        else:
        # 수정시에는 instance 필히 지정
        form = form_class(instance=object)

        return render(request, 'blog/post_update.html', {'form': form})


        # DeleteView CBV
        class PostDelete(DeleteView):
        model = Post
        template_name = 'blog/post_delete.html'
        success_url = reverse_lazy('blog:post_list_cbv')

        # DeleteView FBV
        def postDelete(request, pk):
        post = get_object_or_404(Post, pk=pk)
        if request.method == "POST":
        post.delete()
        return redirect(reverse('blog:post_list_cbv'))
        else:
        return render(request, 'blog/post_delete.html')
  • URL 만들기

    1. reverse

      • 가장 일반적으로 활용하는 메서드
      • URLConf에 있는 패턴 이름과 URL에 들어갈 매개변수 전달
        1
        2
        3
        4
        5
        from django.shortcuts import reverse

        reverse('blog:list')
        reverse('blog:update', args=[1])
        reverse('blog:update', kwargs={'pk':1})
    2. reverse_lazy

      • 클래스형 뷰에서 success_url을 설정할 때
        • reverse를 사용하면 URLConf가 로드되기 전에 동작하므로 오류 발생
        • 이럴 경우, reverse_lazy를 사용
          1
          2
          3
          4
          5
          from django.url import reverse_lazy

          reverse_lazy('blog:list')
          reverse_lazy('blog:update', args=[1])
          reverse_lazy('blog:update', kwargs={'pk':1})
    3. resolve_url

      • reverse의 간략화 버전
        1
        2
        3
        4
        5
        6
        7
        8
        from django.shortcuts import resolve_url

        resolve_url('blog:list')
        resolve_url('blog:update', 1)
        resolve_url('blog:update', pk=1)

        # object의 get_absolute_url을 호출하고 싶은 경우
        resolve_url(object)
    4. redirect

      • URL을 생성하고 해당 URL로 이동하는 redirect response 메세지 생성
        1
        2
        3
        4
        5
        6
        7
        8
        from django.shortcuts import redirect

        redirect('blog:list')
        redirect('blog:update', 1)
        redirect('blog:update', pk=1)

        # object의 get_absolute_url을 호출하고 싶은 경우
        redirect(object)
    5. resolve

      • 주어진 URL로부터 URLConf 정보를 찾아냄
        1
        2
        3
        4
        5
        6
        7
        8
        from django.urls import resolve

        url = resolve(request.path)
        url.route
        url.view_name
        url.url_name
        url.func
        url.kwargs
Share