'web'에 해당하는 글 162건

django middleware

web/Django 2016.08.15 21:36



https://docs.djangoproject.com/ja/1.10/topics/http/middleware/



django에서의 middleware는 모든 request/response의 프로세싱의 훅에 해당합니다. 즉 모든 요청 이벤트를 통과하는 중간 처리과정입니다. 


그렇다면 middleware가 언제 필요한가?! 라고 한다면 


만일 특정 url이 들어왔을 경우에만 처리해야 하는 로직이 있다거나 뷰를 리턴할때마다 무엇인가를 추가하거나 빼거나를 할수도 있습니다. 


즉 특정한 app단에서의 django가 아닌 전체 권한을 가지고 움직일때 쓰이는것이 middleware입니다. ( 윈도우에서의 hooking를 생각하시면 됩니다.)


간단하게 소스로 구현한다면 



testmiddle.py

from django.conf import settings
from django.db import connection
from django.template import Template, Context


class SimpleMiddleware(object):
def __init__(self):
pass
# One-time configuration and initialization.

def process_request(self, request):
return

def process_view(self, request, view_func, view_args, view_kwargs):

print(request, view_args, view_func, view_kwargs)
respose = None
return respose

def process_template_response(self, request, response):
print(request, response)
return response

def process_response(self, request, response):
print(request, response)
return response


파일을 만들어 주고 


settings.py 에서



MIDDLEWARE_CLASSES = [
..................
'post.testMiddle.SimpleMiddleware'
]

MIDDLEWARE_CLASSES = [] 부분에 추가해주면 동작합니다. 쉽죠?!



위의 소스는 간단하게 어떤 함수(훅)이 언제 동작하는지를 간단하게 볼수 있습니다. (django v1.9)


사진출처 : https://docs.djangoproject.com/ja/1.9/topics/http/middleware/#middleware


위의 이미지에서 보는바와 같이 각 요청시에 꼭 통과하는 미들웨어 들이 있고 해당 요청에 따라 작동하는 middleware의 훅이 달라지게 됩니다. 



각 이벤트에 따라 작동하는 훅은 달라지며 특정 요청시에만 훅을 적용하는게 성능상 좋습니다.



좀더 알아보기 위해서 process_response()부분에 다음과 같이 추가합니다.


def process_response(self, request, response):

if connection.queries:
execution_sql_time = sum([float(q['time']) for q in connection.queries])
t = Template(
"""
{{nb_sql}} requet{{nb_sql|pluralize:"e,es"}} en {{execution_sql_time}} second{{execution_sql_time|pluralize:"e,es"}}:
{% for sql in sql_log %}
[{{forloop.counter}}] {{sql.time}}s: {{sql.sql|safe}}
{% endfor %}
""")
print("---------------")
print(t.render(Context({'sql_log':connection.queries,'nb_sql':len(connection.queries),'execution_sql_time':execution_sql_time})))
print("---------------")
print(request, response)
return response

바로 해당 url요청에 실행되는 모든 쿼리와 쿼리 시간을 가져 옵니다. 



정상적으로 잘 가져 오는군요. 이렇듯 django의 전체적인 로직에 관여하고 싶다면 middleware로 구현하면 됩니다. 


단!! 서비스 전체에 걸리는 부하이기 때문에 서비스에 영향이 갈수 있습니다. 


저작자 표시
신고

'web > Django' 카테고리의 다른 글

django middleware  (0) 2016.08.15
django-summernote 사용하기  (4) 2016.07.23
get 방식의 글자 256자 제한은 잘못된 상식  (0) 2016.05.24
Django South migration error   (0) 2015.09.30
django ajax post data and view.py  (0) 2014.11.08
uwsgi logger disable option  (0) 2014.10.24

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret

gulp 실행시 watch 패키지쪽이 에러가 난다면 



uiandwe@uiandwe-box:~/path/to/project/folder$ gulp [21:56:37] Using gulpfile ~/path/to/project/folder/gulpfile.js [21:56:37] Starting 'watch'... [21:56:37] 'watch' errored after 28 ms [21:56:37] Error: watch ENOSPC at errnoException (fs.js:1031:11)





$echo fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p


파일시스템에서 체크할수 있는 파일의 최대치가 설정되어 있는데 이를 수정해 주면 작동한다. (이부분은 처음알았다...신기)

저작자 표시
신고

'web > gulp' 카테고리의 다른 글

gulp Error: watch ENOSPC  (0) 2016.08.01
gulp command does not work  (0) 2016.07.31
ecma6 javascript 를 위한 gulp babel  (0) 2016.06.08
gulp 특정 파일은 제외  (0) 2016.06.02

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret

ubuntu 에서 node와 gulp를 전역으로 설치 했음에도 


/usr/bin/env 
gulp command does not work

라고 에러가 나온다면 다음을 설정해 주자.



$ sudo ln -s /usr/bin/nodejs /usr/bin/node


ubuntu에서 apt-get 으로 설치시 기본 경로가 /usr/bin/nodejs 로 설정되고 패키지들은 /usr/bin/node 로 읽기 때문에 에러가 나는경우가 있다.




저작자 표시
신고

'web > gulp' 카테고리의 다른 글

gulp Error: watch ENOSPC  (0) 2016.08.01
gulp command does not work  (0) 2016.07.31
ecma6 javascript 를 위한 gulp babel  (0) 2016.06.08
gulp 특정 파일은 제외  (0) 2016.06.02

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret

이번 시간에는 rest api 생성시 중요한!!(이라 쓰고 항상 까먹는 부분인..) 참조 url을 만들어보겠습니다.

각 인스턴스마다의 detail url / update url / delete url 를 만들어보겠습니다.




1. post/api/serializers.py에 list 용 시리얼라이져를 따로 만들어줍니다. 

    Meta의 fields 부분을 보면 url이 추가된것을 볼수 있습니다. 


    이때 url은 serializers의 HyperlinkedIdentityField를 씁니다.

    여기서 view_name은 현재 각 urls.py에 쓰였던 name을 써주면 알아서 url을 만들어줍니다. 


   여기서 쓰인 posts-api는 /django-rest-api/urls.py에 쓰인 /api/posts/가 입니다.

   그리고 뒤에 detail 은 /post/api/urls.py 에 있는 /<포스트아이디>/ 가 됩니다. 

   lookup_field 부분은 detail 에 있일 pk부분을 명시해줍니다.


   결국 url 부분은 위의 둘의 url을 알아서 합쳐서 보여줍니다. 


from rest_framework.serializers import ModelSerializer, HyperlinkedIdentityField

class PostListSerializer(ModelSerializer):
url = HyperlinkedIdentityField(
view_name='posts-api:detail',
lookup_field='pk'
)

class Meta:
model = Post
fields = [
'pk',
'user',
'title',
'content',
'created_at',
'url',
]



2. serializer를 새롭게 정의하였으니 post/api/view.py의 PostListAPIView()부분의 시리얼라이져를 위에서 선언한 PostListSerializer()로 변경해 줍니다.


from post.api.serializers import PostSerializer, PostListSerializer


class PostListAPIView(ListAPIView):
serializer_class = PostListSerializer
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['title', 'content']
pagination_class = PostLimitOffsetPagination


3. 이제 /api/posts/화면에서 확인해 보면 리스트에 url부분이 작성되어 리턴된것을 확인 할수 있습니다.




4. post/api/serializers.py 에 update / delete  url을 추가해줍니다.

from rest_framework.serializers import ModelSerializer, HyperlinkedIdentityField

class PostListSerializer(ModelSerializer):
url = HyperlinkedIdentityField(
view_name='posts-api:detail',
lookup_field='pk'
)

delete_url = HyperlinkedIdentityField(
view_name='posts-api:delete',
lookup_field='pk'
)

update_url = HyperlinkedIdentityField(
view_name='posts-api:update',
lookup_field='pk'
)

class Meta:
model = Post
fields = [
'pk',
'user',
'title',
'content',
'created_at',
'url',
'update_url',
'delete_url'
]


5. 다시 /api/posts/로 확인해 보시면 데이터 별로 update/delete url이 추가 된것을 확인 하실수 있습니다.





저작자 표시
신고

'web > Django_rest_framework' 카테고리의 다른 글

9. href  (0) 2016.07.30
8 pagination  (0) 2016.07.29
7 search  (0) 2016.07.28
6 저장/수정시 유저 저장  (0) 2016.07.27
5. create  (0) 2016.07.27
4 update delete  (0) 2016.07.25

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret


이번 포스팅은 앞써 post list화면의 페이지 네이션을 적용하겠습니다.


해당 포스팅에서의 소스파일은 아래 링크에서 확인 가능합니다.

https://github.com/uiandwe/django_rest_api/tree/a923a4cc3c7666c46685021c30ae78292abd91eb



1. 먼저 /posts/api/views.py 파일에서 rest_framework.pagination 과 PostListAPIView()함수에 페이지네이션을 사용한다는 선언을 해줘야 합니다. 


pagination_class는 사용자가 지정한 limit 값만큼 해당 데이터갯수를  혹은 offset으로 지정한 해당 페이지를 돌려줍니다.

자세한 내용은 링크 참조!

http://www.django-rest-framework.org/api-guide/pagination/#modifying-the-pagination-style


from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination

class PostListAPIView(ListAPIView):
serializer_class = PostSerializer
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['title', 'content']
pagination_class = LimitOffsetPagination

def get_queryset(self, *args, **kwargs):
queryset_list = Post.objects.all()
query = self.request.GET.get("q")
if query:
queryset_list = queryset_list.filter(
Q(title__icontains=query) |
Q(content__icontains=query) |
Q(user__first_name__icontains=query) |
Q(user__last_name__icontains=query)
).distinct()
return queryset_list


2.  /api/posts/?limit=2 링크로 실행해보면 아래 화면과 같이 2개의 데이터만을 리턴하는것을 확인할수 있습니다. 





3. /api/posts/?limit=2&offset=2






3. 이번엔 사용자 지정이 아닌 서버내에서 지정하여 작동하게끔 해보겠습니다.


    post/api/pagination.py 파일 생성 후 아래의 소스를 넣어줍니다.

    

   아래의 default_limit의 경우는 특별히 지정되지 않는다면 2개씩 페이지네이션 결과값을 줍니다.

  max_limit의 경우는 사용자가 limit 값으로 지정시의 최대 값으로 사용자가 10 이상을 요청해도 최대 10개씩 돌려줌 입니다.

from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination


class PostLimitOffsetPagination(LimitOffsetPagination):
max_limit = 10
default_limit = 2




4. 위에서 만든 파일을 참조 및 pagination_class에 넣어줍니다.


from post.api.pagination import PostLimitOffsetPagination

class PostListAPIView(ListAPIView):
serializer_class = PostSerializer
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['title', 'content']
pagination_class = PostLimitOffsetPagination

def get_queryset(self, *args, **kwargs):
queryset_list = Post.objects.all()
query = self.request.GET.get("q")
if query:
queryset_list = queryset_list.filter(
Q(title__icontains=query) |
Q(content__icontains=query) |
Q(user__first_name__icontains=query) |
Q(user__last_name__icontains=query)
).distinct()
return queryset_list


5. 다시 /api/posts/를 확인 하면 아까와 같이 2개씩 페이지네이션이 작동하는것을 볼 수 있습니다.


저작자 표시
신고

'web > Django_rest_framework' 카테고리의 다른 글

9. href  (0) 2016.07.30
8 pagination  (0) 2016.07.29
7 search  (0) 2016.07.28
6 저장/수정시 유저 저장  (0) 2016.07.27
5. create  (0) 2016.07.27
4 update delete  (0) 2016.07.25

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret

이번 포스팅은 search에 대한 전반적인 로직을 포스팅할 예정입니다. 


1. 먼저 로그인한 유저의 데이터만 볼수 있도록 list 부분을 수정해 보도록 하겠습니다. 


현재 저장된 데이터는 아래 화면처럼 4개 입니다. 3개는 1번인 admin  / 1개는 3번인 testuser 입니다. 




2. post/api/views.py 에서 PostListAPIView()에 get_queryset()을 오버라이딩 합니다. 


get_queryset()은 GeneriView에서 어떤 데이터를 가져올 것인지에 대한 query를 총괄하는 함수 입니다. 

기존에 사용하던 queryset이 바로 get_queryset 라고 보시면 됩니다. 

파라미터중 self.request 를 통해서 파라미터를 받아서 처리하게끔 하면 됩니다. 

자세한 사항은 아래의 링크를 참조하세요.

http://www.django-rest-framework.org/api-guide/generic-views/#get_querysetself 


이번에는 로그인한 유저의 데이터만을 가져오므로 filter()를 사용해서 user를 매칭시켜 줍니다. 


class PostListAPIView(ListAPIView):
serializer_class = PostSerializer

def get_queryset(self, *args, **kwargs):
queryset_list = Post.objects.filter(user=self.request.user)

return queryset_list


3. 다시 /api/posts/를 보시면 해당 유저의 데이터 리스트만을 리턴해 줍니다. 



4. 이번에는 url파라미터로 q값을 받아서 q와 매칭되는 데이터만을 가져오는것을 해보겠습니다. 

q로 매칭될 데이터들은 title / content / 유저 이름 으로 해보겠습니다. 

filter()의 Q()의 like인 __icontains를 써서 아래와 같이 쿼리를 짰습니다. 그리고 마지막에 .distinct()함수를 통해서 중복을 제거해 줍니다.


from django.db.models import Q
class PostListAPIView(ListAPIView):
serializer_class = PostSerializer

def get_queryset(self, *args, **kwargs):
queryset_list = Post.objects.all()
query = self.request.GET.get("q")
if query:
queryset_list = queryset_list.filter(
Q(title__icontains=query) |
Q(content__icontains=query) |
Q(user__first_name__icontains=query) |
Q(user__last_name__icontains=query)
).distinct()
return queryset_list


5. 이번의 주소는 /api/posts/?q=포스트   입니다. 

타이틀이 포스트이거나 본문 내용이 포스트 이거나 유저 이름이 포스트가 되는 데이터들은 모두 가져오는 거죠. 쉽죠?!



6. 아직 유저 이름은 넣어주지 않았으므로 /admin/에서 user 변경으로 들어갑니다. 


7. 저의 경우 admin유저의 이름을 admin admin 으로 수정하였습니다. 



8. 다시 /api/posts/?q=admin 으로 하면 아래와 같이 admin 유저의 데이터 리스트를 보여줍니다. 




9. 이번엔 쿼리가 아닌 rest_framework.filters 에서 제공하는 search를 구현해 보겠습니다. 

먼저 아래의 searchFilter 과 OrderingFilter를 import합니다. 

그리고 PostListAPIView()에 filter_backends[]와 search_fields[]를 선언해 줍니다. 


filter_backends는 사용할 필터의 정의를 search_fields는 필터링할 컬럼을 정의합니다. 

해당 컬럼은 당연히 시리얼라이져에 정의된 필드를 기준으로 합니다. 

자세한 사항은 아래의 링크를 참조하시면 됩니다. 

http://www.django-rest-framework.org/api-guide/generic-views/#filter_querysetself-queryset

from rest_framework.filters import SearchFilter, OrderingFilter



class PostListAPIView(ListAPIView):
serializer_class = PostListSerializer
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['title', 'content']

def get_queryset(self, *args, **kwargs):
queryset_list = Post.objects.all()
query = self.request.GET.get("q")
if query:
queryset_list = queryset_list.filter(
Q(title__icontains=query) |
Q(content__icontains=query) |
Q(user__first_name__icontains=query) |
Q(user__last_name__icontains=query)
).distinct()
return queryset_list



10. 단지 두줄만 추가 했을뿐인데 작동하니는지 볼까요?

/api/posts/?search=포스트 로 접속해보면 포스트가 저장된 데이터들만 뽑아 오는것을 볼수 있습니다!!


11. 여기에 아까 로직을 만들었던 q도 같이 써보면

/api/posts/?search=저장&q=admin 으로 한다면

admin유저의 포스트중 저장이라고 된 포스트만을 가져오게 됩니다. 


12. 이번엔 ordering 차례 입니다. 

/api/posts/?ordering=pk 로 하시면 pk 내림 차순으로 리턴된것을 볼수 있습니다. 



13. 오름 차순은 -만 붙여주시면 됩니다. 

/api/posts/?ordering=-pk






저작자 표시
신고

'web > Django_rest_framework' 카테고리의 다른 글

9. href  (0) 2016.07.30
8 pagination  (0) 2016.07.29
7 search  (0) 2016.07.28
6 저장/수정시 유저 저장  (0) 2016.07.27
5. create  (0) 2016.07.27
4 update delete  (0) 2016.07.25

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret


이번 포스팅은 기존의 create 와 update시 저장되는 유저의 데이터를 현재 로그인한 유저로 저장되게끔 하는 방법입니다. 

기존의 로직대로라면 처음 저장한 유저의 데이터로 저장되며 수정이 되지 않던 문제를 보강합니다.


해당 포스팅의 모든 소스는 아래 링크에서 확인 가능합니다. https://github.com/uiandwe/django_rest_api/tree/726c4eef6b39872dc3cbd9ca5823e637959aded0



1. 먼저 저장하는 유저를 보기위해서 시리얼라이져에 유저 필드를 추가 합니다. 


post/api/serializers.py

'user' 추가

fields = [
'pk',
'user',
'title',
'content',
'created_at',
]

2. create에 perform_create() / update엔 perform_update()를 오버라이딩 합니다. 

perform_create() / perform_update()는 http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview에서 save and delete hooks부분에서 확인하실수 있습니다. 

각각 create/ update 시 인스턴스에 대한 로직을 구성할때 쓰이는 함수들입니다. ( create시 메일을 보낸다거나 알림을 추가하는 로직을 이곳에 만들어주시면 됩니다.)


post/api/views.py

perform_create() 추가 


class PostCreateAPIView(CreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer

def perform_create(self, serializer):
serializer.save(user=self.request.user)

perform_update() 추가


class PostUpdateAPIView(UpdateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer

def perform_update(self, serializer):
serializer.save(user=self.request.user)


3. 아직 유저가 한명밖에 없으므로 어드민을 새롭게 만들어 줍니다. 저의 경우 testuser로 만들었습니다. 




4.  먼저 /admin/으로 들어가서 기존의 로그이된 유저를 로그아웃 한후 방금전 새로 생성한 유저로 로그인을 합니다. 

그리고 새롭게 /api/posts/create/로 들어가서 user를 기존의 유저(admin)으로 하고 POST 

(오른쪽 상단을 보시면 로그인 유저가 새롭게 생성한 testuser 로 되어 있습니다.)



5. 저장이 완료 되고 저장된 유저가 저의 경우 3번으로 나오는군요. (1번은 admin / 3번은 tsetuser)

정상적으로 작동합니다. 

이번 포스팅에서 중요한점은 perform_create() / perform_update()로 오버라이딩을 할수 있으며 해당 넘어오는 변수들은 self.request 에 되어 있습니다. 필요한 변수들은 해당 request로 인자값이 넘어오니 프로젝트 하실때 도움이 꼭 되실 겁니다. 



저작자 표시
신고

'web > Django_rest_framework' 카테고리의 다른 글

8 pagination  (0) 2016.07.29
7 search  (0) 2016.07.28
6 저장/수정시 유저 저장  (0) 2016.07.27
5. create  (0) 2016.07.27
4 update delete  (0) 2016.07.25
3 get detail 구현  (0) 2016.07.25

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret


이번 시간에는 api중 마지막으로 남은 create를 구현합니다.

post를 새롭게 만들어주는 로직을 rest_Framework로 구현하며

해당 포스팅의 모든 소스는 아래에서 확인하실 수 있습니다.


https://github.com/uiandwe/django_rest_api/tree/4587be2f9f104b5168aba6e8defc414178e5fb3e



1. 먼저 views.py에 create에 대한 뷰를 선언합니다.

rest_Framework의 CreateAPIView 를 사용합니다.



post/api/views.py

from rest_framework.generics import ListAPIView, RetrieveAPIView, DestroyAPIView, UpdateAPIView, CreateAPIView
......

class PostCreateAPIView(CreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer



2. PostCreateAPIView를 작동시킬 url를 추가해 줍니다.

아래는 urls의 모든 소스 입니다. 


post/api/urls.py



from django.conf.urls import url
from django.contrib import admin

from .views import (
PostCreateAPIView,
PostDetailAPIView,
PostListAPIView,
PostUpdateAPIView,
PostDeleteAPIView,

)


urlpatterns = [
url(r'^$', PostListAPIView.as_view(), name='list'),
url(r'^create/$', PostCreateAPIView.as_view(), name='create'),
url(r'^(?P<pk>\d+)/$', PostDetailAPIView.as_view(), name='detail'),
url(r'^(?P<pk>\d+)/edit/$', PostUpdateAPIView.as_view(), name='update'),
url(r'^(?P<pk>\d+)/delete/$', PostDeleteAPIView.as_view(), name='delete'),

]


3. 끝입니다. 간단하죠?!

이제 확인하러!!

/api/posts/create/ 로 접속하면 update화면과 비슷하게 create 화면이 나오게 됩니다. 





4. title과 content 부분에 값을 넣고 post버튼을 눌러주면



5. 새로운 데이터가 생성된것을 확인하실수 있습니다. 



- createAPIView 는 http://www.django-rest-framework.org/api-guide/generic-views/#createapiview 에서 확인하실수 있습니다. 

저작자 표시
신고

'web > Django_rest_framework' 카테고리의 다른 글

7 search  (0) 2016.07.28
6 저장/수정시 유저 저장  (0) 2016.07.27
5. create  (0) 2016.07.27
4 update delete  (0) 2016.07.25
3 get detail 구현  (0) 2016.07.25
2. get method 구현  (0) 2016.07.25

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret


이번 편에서는 입력한 post에 대한 update 와 delete를 구현하겠습니다. 


해당 포스팅의 소스는 아래의 링크에서 확인 하실수 있습니다. 


https://github.com/uiandwe/django_rest_api/tree/70b5380ca66ea6e16e7c41d303f3c68ba3317ded



1. Get과 마찬가지로 generics에서 해당 view를 상속 받아야 합니다. 


     이번에는 DestroyAPIView / UpdateAPIView 입니다. 


     자세한 설명은 http://www.django-rest-framework.org/api-guide/generic-views/#destroyapiview


     post/api/views.py 에 아래의 소스를 추가해 줍니다. 


from rest_framework.generics import ListAPIView, RetrieveAPIView, DestroyAPIView, UpdateAPIView
...
class PostUpdateAPIView(UpdateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer


class PostDeleteAPIView(DestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer



2. post/api/urls.py에 endpoint에 해당하는 url를 추가 해줘야 합니다. 

    먼저 위에 추가한 views를 가져오기 위해 import 에 추가해줘야 하고 


    update 의 url은 /api/posts/포스트 아이디/edit/

    delete는            /api/posts/포스트 아이디/delete/

  

    로 하기위애 아래와 같이 소스를 추가 해줍니다. (아래의 소스는 urls.py의 모든 소스 입니다.)

from django.conf.urls import url
from django.contrib import admin

from .views import (
PostDetailAPIView,
PostListAPIView,
PostUpdateAPIView,
PostDeleteAPIView,

)


urlpatterns = [
url(r'^$', PostListAPIView.as_view(), name='list'),
url(r'^(?P<pk>\d+)/$', PostDetailAPIView.as_view(), name='detail'),
url(r'^(?P<pk>\d+)/edit/$', PostUpdateAPIView.as_view(), name='update'),
url(r'^(?P<pk>\d+)/delete/$', PostDeleteAPIView.as_view(), name='delete'),


]


3. 이제 확인!! 

     먼저 /api/posts/1/ 의 데이터를 확인해봤습니다. 


    저의 경우 타이틀은 first post / content 는 first post content 로 되어 있습니다. 



4. 이제 /api/posts/1/edit/로 가보시면 수정할수 있는 화면이 나옵니다. 

     여기에 title/content를 한글로 모두 수정해봤습니다. 

     수정후 put 버튼 클릭!




5. 다시 detail 화면으로 가시면!! 수정이 정상적으로 작동한것을 확인하실수 있습니다.  




6. 이번엔 delete! 

     /api/posts/에서 리스트를 보시면 두개가 보입니다. 



7. 여기서 /api/posts/1/delete/ 로 1번 데이터를 삭제해 보겠습니다. 

    delete 버튼 클릭!!



8. 다시 delete 버튼을 클릭해 주시면



9. /api/posts/ 화면에서 1번 데이터가 지워진것을 확인하실수 있습니다. delete도 정삭적으로 작동하네요.





10. update / delete 가 너무 간단하셧다면  

   

     update : http://www.django-rest-framework.org/api-guide/generic-views/#updatemodelmixin

     delete  : http://www.django-rest-framework.org/api-guide/generic-views/#destroymodelmixin


     부분을 보시면 더욱 재미있을 것입니다. 각각 update 와 delete를 관장하는 부분으로 나중에 update시 추가 사항이 있거나 delete시 추가 로직이 필요하면 해당 부분을 오버라이딩 하시면 됩니다. 





 

저작자 표시
신고

'web > Django_rest_framework' 카테고리의 다른 글

6 저장/수정시 유저 저장  (0) 2016.07.27
5. create  (0) 2016.07.27
4 update delete  (0) 2016.07.25
3 get detail 구현  (0) 2016.07.25
2. get method 구현  (0) 2016.07.25
1. django rest_framework 셋팅  (0) 2016.07.25

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret


앞써 /api/posts/ 를 통해 post의 데이터를 리턴하는 list endpoint를 구현하였습니다. 

이번에는 리스트가 아닌 하나의 객체를 리턴하는 detail endpoint 를 구현할 포스팅입니다. 


최종적으로 /api/posts/포스트아이디/ 를 통해서 데이터를 리턴하는 페이지를 구현할 것입니다. 


해당 포스팅의 모든 소스는 아래의 링크에서 다운 받을수 있습니다. 

https://github.com/uiandwe/django_rest_api/tree/8b876de0dbaf207ec351a64fcfaf4ee91cf445b6



1. 먼저 detail의 url를 보기 위한 표현 할 정보중 해당 id 를 표현하기 위해 시리얼라이져의filedls에 pk를 추가해 줍니다. 

    post/api/serializers.py


   pk 속성 추가

fields = [
'pk',
'title',
'content',
'created_at',
]



2. /api/posts/ 로 확인해 보면 pk와 해당 데이터가 추가된것을 확인할수 있습니다. 



3. detail 로직을 구현하기 입니다. 

    post/api/views.py 에 rest_framework.generics 의 RetrieveAPIView 를 추가 줍니다. 


    RetrieveAPIView는 오직 하나의 인스턴스만 리턴해 주는 API입니다. 


   (http://www.django-rest-framework.org/api-guide/generic-views/#retrieveapiview)


    그리고 PostDetailAPIView()를 추가해줍니다. 

from rest_framework.generics import ListAPIView, RetrieveAPIView

.....
class PostDetailAPIView(RetrieveAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer


4.  이제 detail 를 표현할 url를 지정해 줘야 겠죠?!


     post/api/urls.py 에 아래의 url를 추가해 줍니다. 

  

    이제 /api/posts/포스트 아이디/ 를 통해서 detail 로직이 구현되었습니다.

urlpatterns = [
.....
url(r'^(?P<pk>\d+)/$', PostDetailAPIView.as_view(), name='detail'),


]


5. 수정!! 

    앞써 작성한 코드중 url이 잘못된 곳이 있습니다.


    django_rest_api/urls.py에 api/posts/ 의 url에서 뒤의 $를 빼줘야 합니다. 

    $의 경우 해당 url의 끝을 의미 하기 때문에 위에서 구현한 /api/posts/포스트 아이디/ 가 작동하지 않기 때문이죠.


이전 소스

url(r'^api/posts/$', include("post.api.urls", namespace="posts-api"))


변경후 소스
url(r'^api/posts/', include("post.api.urls", namespace="posts-api"))



6. 이제 /api/posts/1/로 들어가 보시면!!

    아래와 같이 detail api가 작동하는것을 볼수 있습니다.


7. 여기서 끝!! 이라고 하면 무엇인가 찜찜할 것입니다. 

    사실 소스만 따라하다보면 놓칠수도 있는 부분인데요.


class PostDetailAPIView(RetrieveAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer


위의 함수에서 사실 pk를 받는 부분이 없습니다. 더군다나 Post.objects.all()를 통해서 모든 데이터를 가져왔는데 정확히 우리가 원하는 1번 데이터만을 리턴했습니다. 이상하죠?!


이부분은 RetrieveAPIView 클래스를 보게 되면 의문이 풀립니다. 

RetrieveAPIView는 아래와 같이 정의 되어 있습니다.

class RetrieveAPIView(mixins.RetrieveModelMixin,
GenericAPIView):
"""
Concrete view for retrieving a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)

RetrieveAPIView는 get을 실행하게 되고 get의 kwargs에 통해서 우리가 정의했던 변수들이 넘어가게 됩니다. 현재 정의된 변수는 pk가 되죠.


그래서 view 부분을 아래와 오버라이딩하면 넘어가는 pk값을 확인할수 있습니다. 


class PostDetailAPIView(RetrieveAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer

def get(self, request, *args, **kwargs):
print(kwargs)
return self.retrieve(request, *args, **kwargs)


그 다음에 retrieve에서 해당 pk값에 따른 인스턴스를 찾은후 리턴하게 되는거죠. 


아마도 앞으로 프로젝트를 수행하시다 보면 위와 같이 각 클래스를 오버라이딩 해야만 하는 날이 올수 있을수도 있습니다. (분명히 하게 됩니다. ㅎ) 공식 문서를 통해서 봐도 되자만 사용하는 클래스들을 한번씩 확인해 보시면 코드가 얼마나 깔끔한지 구경도 하는 재미도 있습니다. ㅎ




이번 포스팅은 여기까지 입니다.!!

다음번에는 해당 post 에 대한 update 와 delete를 구현해 보도록 하겠습니다. 



저작자 표시
신고

'web > Django_rest_framework' 카테고리의 다른 글

6 저장/수정시 유저 저장  (0) 2016.07.27
5. create  (0) 2016.07.27
4 update delete  (0) 2016.07.25
3 get detail 구현  (0) 2016.07.25
2. get method 구현  (0) 2016.07.25
1. django rest_framework 셋팅  (0) 2016.07.25

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret