首页 > 解决方案 > 如何使用 DRF 和 HyperlinkedModelSerializer 序列化程序测试 POST 方法

问题描述

我正在使用 Django Rest Framework (DRF),并且正在尝试测试 POST 方法。

这些是我的模型:

class CustomUser(AbstractUser):
    def __str__(self):
        return self.email

    class Meta:
        ordering = ('id',)
        verbose_name = 'user'


class Brand(Group):
    owner = models.ForeignKey(User,
                              on_delete=models.CASCADE,
                              related_name='%(class)ss',
                              related_query_name='%(class)s')
    description = models.TextField('description', max_length=3000, blank=True)
    facebook_url = models.URLField('facebook url', blank=True)
    twitter_url = models.URLField('twitter url', blank=True)
    instagram_url = models.URLField('instagram url', blank=True)
    pinterest_url = models.URLField('pinterest url', blank=True)
    portfolio_url = models.URLField('portfolio url',  blank=True)
    phone_number = PhoneNumberField('phone number', blank=True)

这些是我的序列化程序:

class CustomUserSerializer(HyperlinkedModelSerializer):
    brands = HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='brand-detail'
    )

    class Meta:
        model = CustomUser
        fields = (
            'url',
            'username',
            'email',
            'brands',
        )

class BrandSerializer(HyperlinkedModelSerializer):
    addresses = HyperlinkedRelatedField(many=True,
                                        read_only=True,
                                        view_name='address-detail')

    class Meta:
        model = Brand
        fields = (
            'url',
            'name',
            'owner',
            'description',
            'facebook_url',
            'twitter_url',
            'instagram_url',
            'pinterest_url',
            'portfolio_url',
            'phone_number',
        )

这些是我的看法:

class CustomUserViewSet(ModelViewSet):
    """"A view set for viewing and editing custom users."""
    queryset = CustomUser.objects.all()
    serializer_class = CustomUserSerializer


class BrandViewSet(ModelViewSet):
    """A view set for viewing and editing brands."""
    queryset = Brand.objects.all()
    serializer_class = BrandSerializer

这是我的测试,我正在使用 pytest:

@pytest.mark.django_db
def test_create_brand_with_valid_data(client):
    """Tests POST method with valid data to create a Brand instance."""
    user = CustomUser.objects.create(username='x',
                                     email='x@example.com',
                                     password='abc123', )

    data = {
        'owner': f'http://testserver/api/users/{user.id}/',
        'name': 'NA',
    }

    print(data)

    response = client.post(reverse('address-list'),
                           data=json.dumps(data),
                           content_type='application/json')

    assert response.status_code == HTTP_201_CREATED

我得到的不是 201 响应,而是 400,所以我做错了什么,但我不知道是什么。

追溯:

_________________________________________________________________________________ test_create_brand_with_valid_data _________________________________________________________________________________

client = <django.test.client.Client object at 0x10c2199b0>

    @pytest.mark.django_db
    def test_create_brand_with_valid_data(client):
        """Tests POST method with valid data to create a Brand instance."""
        user = CustomUser.objects.create(username='x',
                                         email='x@example.com',
                                         password='abc123', )

        data = {
            'owner': f'http://testserver/api/users/{user.id}/',
            'name': 'NA',
        }

        print(data)

        response = client.post(reverse('address-list'),
                               data=json.dumps(data),
                               content_type='application/json')

>       assert response.status_code == HTTP_201_CREATED
E       assert 400 == 201
E        +  where 400 = <Response status_code=400, "application/json">.status_code

api/tests/test_brand.py:98: AssertionError

标签: djangodjango-rest-framework

解决方案


这很尴尬,所以问题是我请求错误的端点。下面的代码解决了我的问题,它也避免了对 url 进行硬编码:

import json
from rest_framework.request import Request
from rest_framework.reverse import reverse
from rest_framework.status import (HTTP_200_OK,
                                   HTTP_404_NOT_FOUND,
                                   HTTP_201_CREATED,
                                   HTTP_400_BAD_REQUEST,
                                   HTTP_204_NO_CONTENT)
from rest_framework.test import APIRequestFactory

@pytest.mark.django_db
def test_create_brand_with_valid_data(client):
    """Tests POST method with valid data to create a Brand instance."""
    user = CustomUser.objects.create(username='x',
                                     email='x@example.com',
                                     password='abc123', )
    factory = APIRequestFactory()
    request = factory.get('/')

    context = {'request': Request(request)}
    user_serializer = CustomUserSerializer(user, context=context)

    data = {
        'owner': user_serializer.data['url'],
        'name': 'NA',
    }

    response = client.post(reverse('brand-list'),
                           data=json.dumps(data),
                           content_type='application/json')

    assert response.status_code == HTTP_201_CREATED

这个测试就像一个魅力。


推荐阅读