-
[WebPage] 실전 웹 프로젝트 구축 !!(Server Part 2) - 웹 페이지 제작 강좌Web/WebPage 2015. 7. 9. 11:37
이전 장에 이어서 계속해서 api를 구현하도록 하겠습니다.
연결된 강좌이므로 아래 링크대로 따라주시면 이해가 더 쉬우실 것 입니다.
===========================================
13. 실전 웹 프로젝트(Timeline) Server Part.1
===========================================
17. 다음으로는 사용자 목록을 가져오는 기능을 구현하도록 하겠습니다.
- 사용자 목록 가져오기: api/user/list/
URI
Method
api/user/list/
GET
가입된 사용자 목록을 보여주는 API 입니다.
Input Parameter
None
Output
회원 프로필 리스트
urls.py에 코드를 추가합니다.
1url(r'^api/user/(?P<method>list)/$', user_view),cs user_view에 추가해주도록 합니다. 생성 부분과 수정 부분의 소스는 생략했습니다.
123456789def user_view(request, method):if method == 'create' and request.method == 'POST':skip this sourceelif method == 'update' and request.method == 'POST':skip this sourceelif method == 'list':users = UserProfile.objects.all()else:return HttpResponse('bad request', status=400)cs views.py를 위와 같이 작성해 주시고, models.py를 작성해야합니다.
models.py의 class UserProfile 부분을 아래와 같이 수정해줍니다.
1234567891011121314151617181920212223class UserProfile(models.Model):user = models.OneToOneField(User)nickname = models.CharField(max_length=128)comment = models.TextField()country = models.CharField(max_length=128, blank=True)url = models.CharField(max_length=128, blank=True)ignores = models.ManyToManyField(User, related_name='ignore_set', blank=True, null=True)def __unicode__(self):return "%s" % (self.user,)def serialize(self):data = {'user': self.user_id,'username': self.user.username,'nickname': self.nickname,'comment': self.comment,'country': self.country,'url': self.url,'ignores': [],}return datacs 다시 views.py로 돌아와 아래 코드를 elif list 부분에 추가해줍니다.
123456789101112131415161718import jsondef user_view(request, method):if method == 'create' and request.method == 'POST':skip this sourceelif method == 'update' and request.method == 'POST':skip this sourceelif method == 'list':users = UserProfile.objects.all()serialized = []for u in users:serialized.append(u.serialize())j = json.dumps(serialized, ensure_ascil=False)return HttpResponse(j, content_type='application/json; charset=utf-8')else:return HttpResponse('bad request', status=400)cs 이제 사용자 목록을 확인 할 수 있게 되었습니다. 그런데 뭔가 복잡해 보이기 때문에 모듈화를 해줘야 할 것 같습니다.
views.py 하단에 아래 코드를 추가합니다.
12345678def serialize(objs):return map(lambda x:x.serialize(), objs)def toJSON(objs, status=200):j = json.dumps(objs, encoding="utf-8", ensure_ascii=False)return HttpResponse(j, status=status, content_type='application/json; charset=utf-8')cs 그 다음 user_view 부분을 아래와 같이 수정해줍니다.
1234567891011121314151617181920212223242526272829303132333435363738394041import jsondef user_view(request, method):if method == 'create' and request.method == 'POST':try:username = request.POST.get('username')password = request.POST.get('password')if User.objects.filter(username__exact=username).count():return HttpResponse('duplicate id', 400)user = User.objects.create_user(username, password=password)user.first_name = request.POST.get('name', '')user.save()profile = UserProfile()profile.user = userprofile.save()return toJSON({'status':'create Success'})except:return toJSON({'status':'create failed'}, 400)elif method == 'update' and request.method == 'POST':try:username = request.POST.get('username')password = request.POST.get('password')newpassword = request.POST.get('newpassword')user = User.objects.get(username__exact = username)if user.check_password(password) is False:return toJSON({'status':'wrong password'}, 400)else:user.set_password(newpassword)user.first_name = request.POST.get('name', user.first_name)user.save()except:return toJSON({'status':'bad request'}, 400)return toJSON({'status':'updated'})elif method == 'list':users = UserProfile.objects.all()return toJSON(serialize(users))else:return toJSON({'status':'bad request'}, 400)cs 18. 사용자에 대한 api 구현은 끝이 났습니다. 다음으로는 타임라인 API를 작성하도록 하겠습니다.
- 타임라인 목록 가져오기: api/timeline/
URI
Method
api/timeline/
GET
타임라인 목록을 가져오는 API(로그인 필요)
Input Parameter
page - 가져오고 싶은 페이지
per_page - 한 페이지에 몇 개씩 볼 것인가
Output
{
'total_page': 전체 페이지 수,
'total_count': 전체 메시지 수,
'messages': [{
메시지 정보
}]
}
먼저 UserProfile과 마찬가지로 Message 모델에 serialize 함수를 추가해 줍니다. models.py를 열어서 추가합니다.
123456789101112131415161718class Message(models.Model):user = models.ForeignKey(User)message = models.CharField(max_length=128)created = models.DateTimeField(auto_now_add=True)def serialize(self):data = {'id': self.id,'user': self.user_id,'username': self.user.username,'liked': self.like_set.count(),'message': self.message,'created': self.created.ctime()}return datacs 다음으로 timeline_view를 수정해줍니다.
123456789101112131415161718192021222324252627from django.core.paginator import Paginator@need_authdef timeline_view(request):messages = Message.objects.order_by('-created').all()try:tweet_per_page = int(request.GET.get('per_page', 10))page_num = int(request.GET.get('page', 1))pages = Paginator(messages, tweet_per_page)resp = {'total_page': pages.num_pages,'total_count': pages.count,'messages': serialize(pages.page(page_num).object_list)}return toJSON(resp)except:resp = {'status': 'pagination error'}return toJSON(resp, 400)cs 19. 다음으로 타임라인에 메시지 남기기 기능을 구현하겠습니다.
- 타임라인에 메시지 남기기: api/timeline/create/
URI
Method
api/timeline/create/
POST
타임라인에 메시지를 작성하는 API(로그인 필요)
Input Parameter
message - 가져 오고 싶은 페이지
Output
- 성공시
{'status': 'create success'}
- 실패시
{'status': 'bad request'}
urls.py에 아래 코드를 추가합니다.
12url(r'^api/timeline/create/$', message_create_view),cs 다음으로 views.py에 아래 코드를 추가합니다.
1234567891011121314151617@need_authdef message_create_view(request):if request.method != 'POST':return toJSON({'status': 'bad request'}, 400)message = Message()try:message.user = request.usermessage.message = request.POST.get('message', '')message.save()return toJSON({'status': 'create success'})except:return toJSON({'status': 'bad request'}, 400)cs 타임라인 글 생성이 잘 되는지 확인하기 위해 간단히 Rest Console로 테스트 해보겠습니다.
Request URI를 아래와 같이 설정하고
http://localhost:8000/api/timeline/create/
파라미터를 아래와 같이 설정해줍니다.
설정 뒤 Send 를 눌러서 Response Body 탭을 눌러 아래와 같이 떴는지 확인합니다.
20. 특정 메시지 조회 기능을 구현하도록 하겠습니다.
- 타임라인에서 특정 메시지 조회: api/timeline/메시지ID/
URI
Method
api/timeline/메시지ID/
GET
타임라인에 있는 메시지를 조회하는 API(로그인 필요)
Input Parameter
None
Output
- 성공시
메시지 출력
- 실패시
{'status': 'not found'}
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^api/timeline/(?P<num>\d+)/$', message_view),cs views.py에서 아래 코드를 추가해줍니다.
1234567891011@need_authdef message_view(request, num):try:message = Message.objects.get(id = num)return toJSON(message.serialize())except:return toJSON({'status': 'not found'}, 400)return HttpResponse(None)cs 아까 작성한 메시지를 조회하기 위해 Rest Console을 통해 조회합니다.
http://localhost:8000/api/timeline/1/ 를 URI로 입력하여 파라미터를 지워준 뒤, Send 해서 아래와 같이 뜨는 지 확인합니다.
똑같이 뜨는게 아니라 자신의 아이디나 올린 날짜등은 다를 수 있습니다. JSON으로 내뱉는 게 확실히 나오는 지 확인하기 위함 입니다.
21. 특정 메시지 삭제 기능을 구현하도록 하겠습니다.
- 타임라인에서 특정 메시지 삭제: api/timeline/메시지ID/delete/
URI
Method
api/timeline/메시지ID/delete/
POST
타임라인에 메시지를 삭제하는 API(로그인 필요)
Input Parameter
None
Output
- 성공시
{'status': 'deleted'}
- 실패시
{'status': 'forbidden'}
{'status': 'not found'}
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^api/timeline/(?P<num>\d+)/delete/$', message_delete_view),cs views.py에서 아래 코드를 추가해줍니다.
1234567891011121314@need_authdef message_delete_view(request, num):try:message = Message.objects.get(id = num)if message.user == request.user:message.delete()return toJSON({'status': 'deleted'})else:return toJSON({'status': 'forbidden'}, 401)except:return toJSON({'status': 'not found'}, 400)cs Rest Console로 생성하였던 타임라인 메시지를 삭제합니다. 삭제 기능이 잘 되는지 반응을 살펴보시기 바랍니다. 일일이 확인하는 작업을 올리진 않겠습니다. 후에 클라이언트 페이지를 만들면서도 확인 가능하나 구현 후 바로 확인해보시길 바랍니다.
22. 특정 메시지에 Like 표시하는 기능을 구현하도록 하겠습니다.
- 타임라인에서 특정 메시지 Like 표시: api/timeline/메시지ID/like/
URI
Method
api/timeline/메시지ID/like/
POST
특정 메시지에 Like 표시하는 API(로그인 필요)
Input Parameter
None
Output
- 성공시
{'status': 'created'}
- 실패시
{'status': 'bad request'}
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^api/timeline/(?P<num>\d+)/like/$', like_view),cs views.py에서 아래 코드를 추가해줍니다.
12345678910111213141516@need_authdef like_view(request, num):try:message = Message.objects.get(id=num)like = Like()like.user = request.userlike.message = messagelike.save()except:return toJSON({'status': 'bad request'}, 400)return toJSON({'status': 'created'})cs 23. 타임라인에서 검색하기 기능을 구현하도록 하겠습니다.
- 타임라인에서 검색하기: api/timeline/find/
URI
Method
api/timeline/find/
GET
타임라인에 메시지를 검색하는 API(로그인 필요)
Input Parameter
query - 검색하고 싶은 검색어
Output
- 성공시: 검색한 단어가 포함된 메시지
- 실패시: {'status': 'no'}
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^api/timeline/find/$', find_view),cs views.py에서 아래 코드를 추가해줍니다.
12345678@need_authdef find_view(request):query = request.GET.get('query', '')result = Message.objects.filter(Q(message__contains=query)|Q(user__userprofile__nickname__contains=query))return toJSON(serialize(result))cs 24. 다음으로 사용자의 이름 수정 기능을 구현하도록 하겠습니다.
- 사용자 이름 변경 or 수정하기 : api/user/name/
URI
Method
api/user/name/
GET, POST
현재 로그인한 사용자의 이름을 변경하거나 가져오는 API (로그인 필요)
Input Parameter
POST: 이름 수정
name - 바꾸고자 하는 이름
GET: 이름 가져오기
None
Output
1. 이름 수정 시(POST)
- 성공시: {'status': 'updated'}
- 실패시: {'status': 'bad request'}
2. 이름 가져올 때(GET)
{'name': 이름}
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^api/user/name/$', name_view),cs views.py에서 아래 코드를 추가해줍니다.
1234567891011121314151617181920@need_authdef name_view(request):if request.method == 'GET':data = {'name': request.user.first_name,}return toJSON(data)if request.method == 'POST':try:name = request.POST.get('name')request.user.first_name = namerequest.user.save()return toJSON({'status': 'updated'})except:return toJSON({'status': 'bad request'}, 400)cs 25. 암호를 확인하고 설정하는 API를 구현하도록 하겠습니다.
- 암호를 확인하고 설정하기 : api/user/checkpassword/, api/user/setpassword/
URI
Method
api/user/checkpassword/
POST
현재 로그인 한 사용자의 비밀번호가 맞는지 확인하는 API (로그인 필요)
Input Parameter
password - 비밀번호
Output
비밀번호 맞을 때: {'status': 'ok'}
비밀번호 틀릴 때: {'status': 'no'}
URI
Method
api/user/setpassword/
POST
현재 로그인 한 사용자의 비밀번호를 변경하는 API (로그인 필요)
Input Parameter
password - 비밀번호
Output
비밀번호 변경 성공 시: {'status': 'ok'}
urls.py에 아래와 같은 코드를 입력합니다.
123url(r'^api/user/checkpassword/$', checkpassword_view),url(r'^api/user/setpassword/$', setpassword_view),cs views.py에서 아래 코드를 추가해줍니다.
12345678910111213141516171819202122232425@need_authdef checkpassword_view(request):try:password = request.POST.get('password')if request.user.check_password(password):return toJSON({'status': 'OK'})except:passreturn toJSON({'status': 'no'})@need_authdef setpassword_view(request):try:password = request.POST.get('password')if password:request.user.set_password(password)request.user.save()return toJSON({'status': 'OK'})except:passreturn toJSON({'status': 'no'})cs 26. Profile을 조회하는 API를 구현하도록 하겠습니다.
- Profile 조회하기 : api/profile/사용자아이디/
URI
Method
api/profile/사용자아이디/
GET
URI에 명시된 사용자의 프로필을 가져오는 API
Input Parameter
None
Output
URI에 명시된 사용자의 프로필
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^api/profile/(?P<username>\w+)/$', profile_view),cs views.py에서 아래 코드를 추가해줍니다.
12345678910111213@need_authdef profile_view(request, username):if request.method == 'GET':try:userprofile = User.objects.get(username=username).userprofilereturn toJSON(userprofile.serialize())except:return toJSON({'status': 'not found'}, 400)cs 27. 현재 로그인한 사용자의 프로필을 가져오거나 수정하는 API를 구현하도록 하겠습니다.
urls.py에 아래와 같은 코드를 입력합니다.
1234url(r'^api/profile/$', profile_view),cs views.py에서 아래 코드를 추가해줍니다. 기존의 profile_view에 username 파라미터가 없을 때, POST 형식으로 받았을 때를 추가하겠습니다.
123456789101112131415161718192021222324252627282930@need_authdef profile_view(request, username=None):if username == None:username = request.userif request.method == 'GET':try:userprofile = User.objects.get(username=username).userprofilereturn toJSON(userprofile.serialize())except:return toJSON({'status': 'not found'}, 400)elif request.method == 'POST':profile = request.user.userprofileprofile.nickname = request.POST.get('nickname', profile.nickname)profile.comment = request.POST.get('comment', profile.comment)profile.country = request.POST.get('country', profile.country)profile.url = request.POST.get('url', profile.url)ignores = request.POST.get('ignore', None)if ignores:ignores = json.loads(ignores)profile.set_ignorelist(ignores)profile.save()return toJSON({'status': 'updated'})cs 다음으로 ignore 속성에 대한 설정이 없었으므로, models.py를 수정하도록 하겠습니다.
1234567891011121314151617181920212223242526272829303132333435363738394041class UserProfile(models.Model):user = models.OneToOneField(User)nickname = models.CharField(max_length=128)comment = models.TextField()country = models.CharField(max_length=128, blank=True)url = models.CharField(max_length=128, blank=True)ignores = models.ManyToManyField(User, related_name='ignore_set', blank=True, null=True)def __unicode__(self):return "%s" % (self.user,)def get_ignorelist(self):ignores = []for k in self.ignores.all():ignores.append(k.id)return ignoresdef set_ignorelist(self, ignores):self.ignores = []for k in ignores:try:ignore = User.objects.get(id = k)self.ignores.add(ignore)self.save()except:passdef serialize(self):data = {'user': self.user_id,'username': self.user.username,'nickname': self.nickname,'comment': self.comment,'country': self.country,'url': self.url,'ignores': self.get_ignorelist(),}return datacs 마지막으로 timeline_view를 수정하여서 api 구현을 완료합니다.
123456789101112131415161718192021222324252627@need_authdef timeline_view(request):messages = Message.objects.order_by('-created').all()ignore = request.user.userprofile.get_ignorelist()messages = messages.exclude(user__id__in = ignore)try:tweet_per_page = int(request.GET.get('per_page', 10))page_num = int(request.GET.get('page', 1))pages = Paginator(messages, tweet_per_page)resp = {'total_page': pages.num_pages,'total_count': pages.count,'messages': serialize(pages.page(page_num).object_list)}return toJSON(resp)except:resp = {'status': 'pagination error'}return toJSON(resp, 400)cs 28. 정상적으로 로그인 되었는지 확인하는 API를 구현하도록 하겠습니다.
- 로그인 확인하기 : api/login/
URI
Method
api/login/
GET
로그인 테스트에 사용할 API
Input Parameter
None
Output
{'status': 'ok', ,'user': 로그인 한 사용자의 프로필 }
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^api/login/$', login_view),cs views.py에서 아래 코드를 추가해줍니다.
1234@need_authdef login_view(request):return toJSON({'status': 'OK', 'user':request.user.userprofile.serialize()})cs 28. 마지막으로 Template Page를 설정하겠습니다.
지금까지 우리는 Django를 이용해 API를 개발하였습니다. 여기에는 템플릿을 사용하지도 않았고 HTML을 쓰지도 않았습니다.
하지만 실제 서비스를 운영하려면 API만 가지고는 불가능 합니다. 아래 방법을 통해 html 페이지를 제공하기 위한 방법을 확인하면서 서버 부분을 마치겠습니다.
urls.py에 아래와 같은 코드를 입력합니다.
12url(r'^home/(?P<page>\w+).html$', serve_html),cs views.py에서 아래 코드를 추가해줍니다.
12345from django.shortcuts import render_to_responsedef serve_html(reqeust, page):return render_to_response(page+'.html')cs 여기까지 작성으로 Server 딴에서의 작업은 끝이 났습니다.
모든 기능에 이상이 없는지 체크하시고 다음 장에서 뵙도록 하겠습니다.
질문 사항은 댓글/ DISQUS를 통해 달아주세요.
* 본 포스팅은 이재근 등 4명 저 "Fast Web Service Build up: 웹 서비스를 쉽고 빠르게 구축하는 기술" 저서를 참고하여 작성하였습니다
'Web > WebPage' 카테고리의 다른 글
[WebPage] 실전 웹 프로젝트 구축 !!(Client Part 3) - 웹 페이지 제작 강좌 (0) 2015.07.11 [WebPage] 실전 웹 프로젝트 구축 !!(Client Part 2) - 웹 페이지 제작 강좌 (0) 2015.07.11 [WebPage] 실전 웹 프로젝트 구축 !!(Client Part 1) - 웹 페이지 제작 강좌 (0) 2015.07.09 [WebPage] 실전 웹 프로젝트 구축 !!(Server Part 1) - 웹 페이지 제작 강좌 (0) 2015.07.08 [WebPage] 실전 웹 프로젝트 구축 !!(실전 예제) - 웹 페이지 제작 강좌 (0) 2015.07.07 [WebPage] 4. 웹 프로그래밍의 필수요소, JavaScript와 jQuery - 웹 페이지 제작 강좌 (1) 2015.07.07