# Django REST Framework
###### tags: `Django` `REST`
# 零、參考文件
[關於 Django REST framework 的一些筆記](https://blog.m157q.tw/posts/2018/01/07/django-rest-framework-note/)
[encode/django-rest-framework](https://github.com/encode/django-rest-framework)
[manosim/django-rest-framework-docs](https://github.com/manosim/django-rest-framework-docs)
[Django REST framework](https://www.django-rest-framework.org/)
[Document Web APIs made with Django REST Framework.](https://www.drfdocs.com/)
[twtrubiks/django-rest-framework-tutorial](https://github.com/twtrubiks/django-rest-framework-tutorial)
[Day 19: 關於 Django REST framework 的一些筆記](https://ithelp.ithome.com.tw/articles/10196385)
[How to write an API in 3 lines of code with Django REST framework](https://medium.com/crowdbotics/how-to-write-an-api-in-3-lines-of-code-with-django-rest-framework-59b0971edfa4)
> 這篇講一些概念
[Let’s build an API with Django REST Framework](https://medium.com/backticks-tildes/lets-build-an-api-with-django-rest-framework-32fcf40231e5)
[Creating a Django API using Django Rest Framework APIView](https://medium.com/the-andela-way/creating-a-django-api-using-django-rest-framework-apiview-b365dca53c1d)
> 這篇利用 Class based View - ``APIView``實作``GET``/``POST``/``PUT``/``DELETE``
[Creating a DjangoRest API using DjangoRestFramework part 2.](https://medium.com/the-andela-way/creating-a-djangorest-api-using-djangorestframework-part-2-1231fe949795)
> 介紹``GenericAPIView``, 若在 List, Detail顯示需求之下,
若使用 ``ListAPIView`` 就不必寫 ``get()``
若使用 ``CreateAPIView`` 就不用寫 ``post()``
``ListCreateAPIView`` 可以取代 ``CreateAPIView`` + ``ListAPIView``, 同時支讀取看與更新列表資料;
顯示Detail (單一資料用)有:
> - ``RetrieveUpdateAPIView`` 同時支讀取看與更新
> - ``RetrieveAPIView``只有讀取
[Building an API with Django REST Framework and Class-Based Views
](https://codeburst.io/building-an-api-with-django-rest-framework-and-class-based-views-75b369b30396)
[Official Django REST Framework Tutorial - A Beginners Guide](https://wsvincent.com/official-django-rest-framework-tutorial-beginners-guide/)
[Django Rest Framework - Blog API](https://wsvincent.com/django-rest-framework-tutorial/)
[Speed up Django Nested Foreign Key Serializers w/ prefetch_related](https://medium.com/quant-five/speed-up-django-nested-foreign-key-serializers-w-prefetch-related-ae7981719d3f)
[Dealing with unique constraints in nested serializers](https://medium.com/django-rest-framework/dealing-with-unique-constraints-in-nested-serializers-dade33b831d9)
[Nested Relationships in Serializers for OneToOne fields in Django Rest Framework](https://medium.freecodecamp.org/nested-relationships-in-serializers-for-onetoone-fields-in-django-rest-framework-bdb4720d81e6)
# 常用的 classes/ code snippet
### Url 區塊:
在 ``urlpatterns`` 陣列中,透過 ``path()``,存取 ``view.index``
```
urlpatterns = [
path('', views.index, name='index'),
]
```
### model:
#### Django
```
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
class Foo(models.Model):
#definition of fields:
question_text = models.CharField(max_length=200)
title = models.CharField(max_length=100, blank=True, default='')
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
pub_date = models.DateTimeField('date published')
created = models.DateTimeField(auto_now_add=True)
votes = models.IntegerField(default=0)
# RefObject is other model class
refObject = models.ForeignKey(RefObject, on_delete=models.CASCADE)
#author = models.ForeignKey(Author, related_name='articles', on_delete=models.CASCADE)
description = models.TextField()
email = models.EmailField()
linenos = models.BooleanField(default=False)
class Meta:
ordering = ('created',)
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
```
### Serializer
#### Django Rest Framework
```
from rest_framework import serializers
class ArticleSerializer(serializers.Serializer):
title = serializers.CharField(max_length=120)
description = serializers.CharField()
body = serializers.CharField()
author_id = serializers.IntegerField()
def create(self, validated_data):
return Article.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.title = validated_data.get('title', instance.title)
instance.description = validated_data.get('description', instance.description)
instance.body = validated_data.get('body', instance.body)
instance.author_id = validated_data.get('author_id', instance.author_id)
instance.save()
return instance
class ArticleSerializer2(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'description', 'body', 'author_id')
```
### View
#### 1. Django:
有原生的 ``View``嗎? ---> 目前尚未 subclass 過!
#### 2. Django Rest Framework:
##### ``APIView``:
```
from rest_framework.views import APIView
class ArticleView(APIView):
# HTTP GET
def get(self, request):
#articles = Article.objects.all()
#return Response({"articles": articles})
# the many param informs the serializer that it will be serializing more than a single article.
# what does 'many=true' mean?
serializer = ArticleSerializer(articles, many=True)
return Response({"articles": serializer.data})
# HTTP POST
def post(self, request):
article = request.data.get('article')
# Create an article from the above data
serializer = ArticleSerializer(data=article)
# what does 'raise_exception=true' mean?
if serializer.is_valid(raise_exception=True):
article_saved = serializer.save()
return Response({"success": "Article '{}' created successfully".format(article_saved.title)})
def put(self, request, pk):
saved_article = get_object_or_404(Article.objects.all(), pk=pk)
data = request.data.get('article')
serializer = ArticleSerializer(instance=saved_article, data=data, partial=True)
if serializer.is_valid(raise_exception=True):
article_saved = serializer.save()
return Response({"success": "Article '{}' updated successfully".format(article_saved.title)})
def delete(self, request, pk):
# Get object with this pk
article = get_object_or_404(Article.objects.all(), pk=pk)
article.delete()
return Response({"message": "Article with id `{}` has been deleted.".format(pk)},status=204)
```
##### ``GenericAPIView``:
```
from rest_framework.generics import get_object_or_404, GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin
class ArticleView2(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer2
def get(self, request, *args, **kwargs):
print("goes through ArticleView2")
#involve .list() method
return self.list(request, *args, *kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def perform_create(self, serializer):
author = get_object_or_404(Author, id=self.request.data.get('author_id'))
return serializer.save(author=author)
```
##### ``RetrieveUpdateAPIView`` / ``RetrieveAPIView``:
```
from rest_framework.generics import RetrieveUpdateAPIView, RetrieveAPIView
class SingleArticleView(RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer2
```