© 2020, Developed by Hieu Dev

Tổng hợp 10 tips hữu ích khi làm việc với Django REST framework hiệu quả (P2)

Như các bạn biết, Django REST framework là một framework tuyệt vời để phát triển web với python, hiện tại nó đang rất phổ biến và được nhiều người tiếp cận. Cụ thể các ông lớn đã áp dụng công nghệ này chẳng hạn như Instagram, Pinterest, Youtube, Spotify, Bitbucket,...

Tổng hợp 10 tips hữu ích khi làm việc với Django REST framework hiệu quả (P2)

1. Tắt pagination tự động 

Khi bạn làm việc với DRF ModelViewSet, có lẽ bạn sẽ dùng đến pagination, nhưng bạn chỉ muốn thêm pagination cho một list view nhất định, còn list khác thì không. Để tắt pagination trên mỗi class cụ thể, bạn có thể dùng cách sau:

class MyClassBasedView(ModelViewSet):
    pagination_class = None
    ...

2. Environment variables

Trong DRF, chúng ta cũng có thể setup các biến môi trường, chẳng hạn như bạn muốn tạo ra một các biến môi trường cho database name, hay các secret key,...

Đầu tiên, bạn cần cài đặt Django Environ, bằng lệnh sau:

$ pip install django-environ


Tiếp theo, bạn cần thêm một số thiết lập quan trọng trong settings.py:

import environ
# Initialise environment variables
env = environ.Env()
environ.Env.read_env()

Bây giờ, bạn cần tạo file .env để thêm các variables của bạn, ví dụ trong file .env có nhưng khai báo sau:

 
SECRET_KEY=h^z13$qr_s_wd65@gnj7a=xs7t05$w7q8!x_8zsld#
DATABASE_NAME=postgresdatabase
DATABASE_USER=alice
DATABASE_PASS=supersecretpassword

Để sử dụng các .env, ví dụ thay thế các giá trị bên trong settings.py sử dụng các giá trị trong .env như sau:
DATABASES = {
    `default`: {
        `ENGINE`: `django.db.backends.postgresql_psycopg2`,
        `NAME`: env(`DATABASE_NAME`),
        `USER`: env(`DATABASE_USER`),
        `PASSWORD`: env(`DATABASE_PASS`),
    }
}


3. Lưu trạng thái sau mỗi lần create/update/delete

Trong DRF, bạn có thể lưu lịch sử sau mỗi lần tương tác với model, cụ thể là khi thực hiện create/ update/ delete dữ liệu. Bạn có thể dễ dàng làm điều này khi sử dụng django-simple-history. Cụ thể như các bước dưới đây:

Đâu tiên, ta cần install django-simple-history với command sau:

$ pip install django-simple-history


Tiếp theo cần thiết lập bằng cách thêm simple_history vào INSTALLED_APPS:

INSTALLED_APPS = [
    # ...
    'simple_history',
]

Các historical models có thể theo dõi ai đã thực hiện sau mỗi thay đổi. Để tự động cập nhật, ta cần thêm HistoryRequestMiddleware vào Django settings:

 
MIDDLEWARE = [
    # ...
    'simple_history.middleware.HistoryRequestMiddleware',
]

Bây giờ, để theo dõi lịch sử cho một model, ta chỉ cần thêm simple_history.models.HistoricalRecords vào model đó. Cụ thể ta có ví dụ sau:

 
from django.db import models
from simple_history.models import HistoricalRecords

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    history = HistoricalRecords()

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    history = HistoricalRecords()


Bây giờ, bạn chỉ cần migrations và xem kết quả trên database.

4. Truy cập item detail bằng slug thay vì Id

Mặc định khi bạn xem chi tiết item thì sẽ truy cập theo Id, với slug nó cũng là duy nhất, và để truy cập chi tiết item theo slug, dưới đây là giải pháp:

Trước tiên, ta cần thêm lookup_field trong serializer:
 
class ItemSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Item
        fields = ('url', 'slug', 'title', 'item_url')
        lookup_field = 'slug'
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

Và trong view sẽ như sau:
 
class ItemViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer
    lookup_field = 'slug'


5. Additional field trong serializer

Để bổ sung các trường không thuộc trong thiết kế của bạn, chẳng hạn bạn muốn thêm một trường fullname với fullname được gộp lại từ firstname và lastname.

Để làm điều này, ta có 2 cách như dưới đây:

Cách 1: Sử dụng readonly field với source

# models.py
class Employees(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    @property
    def full_name(self):
        return self.first_name + self.last_name

# serializers.py
class EmployeeSerializer(serializers.ModelSerializer):
    full_name = serializers.Field(source='full_name')

    class Meta:
        model = Employees
        fields = ('first_name','last_name', 'full_name')


Cách 2: Sử dụng SerializerMethodField

class EmployeeSerializer(serializers.ModelSerializer):
    full_name = serializers.SerializerMethodField('get_full_name')

    def get_full_name(self, obj):
        return obj.first_name + obj.last_name

    class Meta:
        model = Employees
        fields = ('first_name','last_name', 'full_name')


6. Return results from multiple models

Đây là một tips khá hay, khi bạn muốn trả về nhiều models trong một method, ví dụ bạn có một Timeline và khi get list, bạn cần lấy về lượng Tweet lên artical và list Article:

Đây là 2 cách khi sử dụng với ModelViewSet và ListAPIView.

Cách 1: Sử dụng ModelViewSet:

class TimelineViewSet(viewsets.ModelViewSet):
    def list(self, request):
        queryset = list(itertools.chain(Tweet.objects.all(), Article.objects.all()))
        serializer = TimelineSerializer(queryset, many=True)
        return Response(serializer.data)

Cách 2: Sử dụng ListAPIView:

class TimeLineList(generics.ListAPIView):
    serializer_class = TimeLineSerializer

    def get_queryset(self):
        return list(itertools.chain(Tweet.objects.all(), Article.objects.all()))


7. Upload multiple files

Để thực hiện upload nhiều files trong DRF, mình giới thiệu các bạn giải pháp sau:

Thêm FileListSerializer trong serializers.py:

class FileListSerializer ( serializers.Serializer ) :
    image = serializers.ListField(
                       child=serializers.FileField( max_length=100000,
                                         allow_empty_file=False,
                                         use_url=False )
                                )
    def create(self, validated_data):
        blogs=Blogs.objects.latest('created_at')
        image=validated_data.pop('image')
        for img in image:
            photo=Photo.objects.create(image=img,blogs=blogs,**validated_data)
        return photo

class PhotoSerializer(serializers.ModelSerializer):

    class Meta:
        model = Photo
        read_only_fields = ("blogs",)


Cập nhật serializer_class FileListSerializer trong views.py:

 
class PhotoViewSet(viewsets.ModelViewSet):
    serializer_class = FileListSerializer
    parser_classes = (MultiPartParser, FormParser,)
    queryset=Photo.objects.all()


8. Ẩn endpoint trong SwaggerUI

Để ẩn một số endpoint tùy chỉnh bên trong SwaggerUI, các bạn có thể set lại swagger_schema:

class InvoicesView(APIView):

    @swagger_auto_schema(swagger_schema=None)
    def get(self, request, **kwargs):
    ...


Lời kết 

Trong đây là những tips cơ bản hay gặp trong quá trình bạn làm việc với DRF, những hàm hữu dụng sẽ có trong các bài tiếp theo. Mong bài viết hữu ích với các bạn.

Hieu Ho.

Đăng nhận xét

Mới hơn Cũ hơn