如果这个问题已经在其他地方得到了回答,请原谅.我找不到一个适合我的情况的答案.

我是新来的Django ,所以我觉得问题是我没有从根本上掌握一个大概是基本的概念……

使用DRF和PYTEST-Django,我努力做到勤奋,在手动测试变得太耗时之前,在此过程中编写测试.我可以看到它滚雪球滚雪球相当快.

我面临的问题是,当我try 测试目录的创建时,我无法让它将User实例传递给必填字段‘Created_by’.当我手动测试时,逻辑运行得很好,但编写测试本身让我头疼.

首先要感谢大家!

错误是: TypeError:无法将键‘Created_by’的NONE编码为POST数据.您是要传递空字符串还是省略该值?

提供的代码.

# core/models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
    email = models.EmailField(unique=True)


# workshop/models.py
from django.conf import settings
from django.db import models

class Catalogue(models.Model):
    STATE_DRAFT = 'DRAFT'
    STATE_PUBLISHED_PRIVATE = 'PUBPRIV'
    STATE_PUBLISHED_PUBLIC = 'PUBPUB'

    STATE_CHOICES = [
        (STATE_DRAFT, 'Draft'),
        (STATE_PUBLISHED_PRIVATE, 'Published (Private)'),
        (STATE_PUBLISHED_PUBLIC, 'Published (Public)')
    ]
    company = models.ForeignKey(Company, on_delete=models.PROTECT)
    title = models.CharField(max_length=255)
    description = models.TextField(null=True, blank=True)
    state = models.CharField(
        max_length=10, choices=STATE_CHOICES, default=STATE_DRAFT)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
    created_on = models.DateTimeField(auto_now_add=True)

    def __str__(self) -> str:
        return self.title

class CatalogueItem(models.Model):
    TYPE_GOODS = 'GOODS'
    TYPE_SERVICES = 'SERVICES'
    TYPE_GOODS_AND_SERVICES = 'GOODS_AND_SERVICES'

    TYPE_CHOICES = [
        (TYPE_GOODS, 'Goods'),
        (TYPE_SERVICES, 'Services'),
        (TYPE_GOODS_AND_SERVICES, 'Goods & Services')
    ]
    catalogue = models.ForeignKey(
        Catalogue, on_delete=models.CASCADE, related_name='catalogueitems')
    type = models.CharField(
        max_length=50, choices=TYPE_CHOICES, default=TYPE_GOODS)
    name = models.CharField(max_length=255)
    description = models.TextField()
    unit_price = models.DecimalField(max_digits=9, decimal_places=2)
    can_be_discounted = models.BooleanField(default=True)

    def __str__(self) -> str:
        return self.name

    @property
    def item_type(self):
        return self.get_type_display()


# workshop/serializers.py
class CatalogueSerializer(serializers.ModelSerializer):
    catalogueitems = SimpleCatalogueItemSerializer(
        many=True, read_only=True)
    created_on = serializers.DateTimeField(read_only=True)
    created_by = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        # depth = 1
        model = Catalogue
        fields = ['id', 'title', 'description',
                  'state', 'catalogueitems', 'created_by', 'created_on']

    def create(self, validated_data):
        company_id = self.context['company_id']
        user = self.context['user']
        return Catalogue.objects.create(company_id=company_id, created_by=user, **validated_data)

# workshop/views.py
class CatalogueViewSet(ModelViewSet):
    serializer_class = CatalogueSerializer

    def get_permissions(self):
        if self.request.method in ['PATCH', 'PUT', 'DELETE', 'POST']:
            return [IsAdminUser()]
        return [IsAuthenticated()]

    def get_queryset(self):
        user = self.request.user
        if user.is_staff:
            return Catalogue.objects.prefetch_related('catalogueitems__catalogue').filter(company_id=self.kwargs['company_pk'])
        elif user.is_authenticated:
            return Catalogue.objects.filter(company_id=self.kwargs['company_pk'], state='PUBPUB')

    def get_serializer_context(self):
        company_id = self.kwargs['company_pk']
        return {'company_id': company_id, 'user': self.request.user}

# workshop/tests/conftest.py
from core.models import User
from rest_framework.test import APIClient
import pytest


@pytest.fixture
def api_client():
    return APIClient()


@pytest.fixture
def authenticate(api_client):
    def do_authenticate(is_staff=False):
        return api_client.force_authenticate(user=User(is_staff=is_staff))
    return do_authenticate


# workshop/tests/test_catalogues.py
from core.models import User
from workshop.models import Catalogue
from rest_framework import status
import pytest

@pytest.fixture
def create_catalogue(api_client):
    def do_create_catalogue(catalogue):
        return api_client.post('/companies/1/catalogues/', catalogue)
    return do_create_catalogue

class TestCreateCatalogue:
    def test_if_admin_can_create_catalogue_returns_201(self, authenticate,  create_catalogue):
        
        user = authenticate(is_staff=True)
        response = create_catalogue(
            {'title': 'a', 'description': 'a', 'state': 'DRAFT','created_by':user})

        assert response.status_code == status.HTTP_201_CREATED

推荐答案

我认为您可能对用来进行测试的用户有问题,

当您调用身份验证时,它返回一个与用户不同的客户端.

然后运行身份验证并以普通用户身份登录.try 制作另一个装置,首先创建一个用户,向该用户进行身份验证以返回客户端,然后将您创建的用户发布到create_catalogue

from django.conf import settings

@pytest.fixture
def create_user() -> User:
    return settings.AUTH_USER_MODEL.objects.create(
        username="Test User", password="Test Password", email="testuser@example.com"
    )

@pytest.fixture
def authenticate(api_client):
    def do_authenticate(create_user):
        return api_client.force_authenticate(create_user)
    return do_authenticate

class TestCreateCatalogue:
    def test_if_admin_can_create_catalogue_returns_201(self, authenticate, create_user  create_catalogue):
        
        user = authenticate(create_user)
        response = create_catalogue(
            {'title': 'a', 'description': 'a', 'state': 'DRAFT','created_by':create_user})

        assert response.status_code == status.HTTP_201_CREATED

Django相关问答推荐

使用django直接计算geohash而不创建模型

Django-无法显示基于字段值的元素

Django 中主键的隐式 UUID 自动字段

Django 相当于子查询

什么时候在 django rest 框架序列化程序中调用创建和更新?

Django中基于令牌的身份验证

变量为无时默认模板标签输出的Django设置?

django 在 ubuntu 中安装在哪里

在 Django 中,您可以向查询集添加方法吗?

UnicodeDecodeError:asciicodec can't decode byte 0xe0 in position 0: ordinal not in range(128)

用户组和权限

在 virtualenv Ubuntu 12.10 中使用 pip 安装 lxml 错误:command 'gcc' failed with exit status 4

测试 Django 信号的正确方法

使用 get_object_or_404 获取数据库值

Django中的自定义排序

Django:DoesNotExist从何而来?

Django Admin - save_model 方法 - 如何检测字段是否已更改?

Django模板过滤器(filters)、标签(tags)、simple_tags和inclusion_tags

Django - 指定 Django 管理员应该使用哪个模型管理器

Django中'related_name'和'related_query_name'属性之间的区别?