Django 无法同时更新自定义用户和 UserProfile 模型

问题描述 投票:0回答:1

我正在开发 Django 项目,我的测试用例遇到了一些问题。具体来说,我在与用户配置文件更新和用户创建相关的两个测试用例方面遇到问题。

有人可以帮助我确定可能导致这些测试失败的原因以及如何修复它们吗?任何见解或指导将不胜感激。

这是我收到的错误消息:

======================================================================
FAIL: test_update_user_profile (user.tests.test_user_api.PrivateUserApiTests)
Test updating the user profile for the authenticated user.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/app/user/tests/test_user_api.py", line 301, in test_update_user_profile
    self.assertEqual(self.profile.bio, payload['profile']['bio'])
AssertionError: 'Profile bio.' != 'Updated bio.'
- Profile bio.
+ Updated bio.
======================================================================
FAIL: test_create_user_success (user.tests.test_user_api.PublicUserApiTests)
Test creating a user is successfull.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/app/user/tests/test_user_api.py", line 95, in test_create_user_success
    self.assertEqual(res.status_code, status.HTTP_201_CREATED)
AssertionError: 400 != 201

test_user_api.py

CREATE_USER_URL = reverse('user:create')
ME_URL = reverse('user:me')

def create_user(**params):
    return get_user_model().objects.create_user(**params)

def create_profile(user, **params):
    defaults = {
        'picture': None,
        'bio': 'My bio.',
        'dob': '2000-12-12',
    }
    defaults.update(params)
    return UserProfile.objects.create(user=user, **defaults)


class PublicUserApiTests(TestCase):

    def setUp(self):
        self.client = APIClient()

    def test_create_user_success(self):
        payload = {
            'name': 'Test Name',
            'email': '[email protected]',
            'password': 'testpass123',
            'profile': {
                'picture': None,
                'bio': 'Create bio.',
                'dob': '2000-01-01',
            }
        }
        res = self.client.post(CREATE_USER_URL, payload, content_type='application/json')
        self.assertEqual(res.status_code, status.HTTP_201_CREATED)


class PrivateUserApiTests(TestCase):
    """Test API requests that require authentication."""

    def setUp(self):
        self.user = create_user(
            name='Test Name',
            email='[email protected]',
            password='testpass123',
        )
        self.profile = create_profile(
            user=self.user,
            picture=None,
            bio="Profile bio.",
            dob="2017-05-27",
        )
        self.client = APIClient()
        self.client.force_authenticate(user=self.user)

    def test_update_user_profile(self):
        payload = {
            'name': 'Updated Name',
            'email': '[email protected]',
            'password': 'newpassword123',
            'profile': {
                'picture': None,
                'bio': 'Updated bio.',
                'dob': '2022-02-02',
                }
        }
        res_profile = self.client.patch(ME_URL, payload, format='json')
        self.user.refresh_from_db
        self.profile.refresh_from_db()
        self.assertEqual(self.profile.bio, payload['profile']['bio'])

Urls.py:

path('create/', views.CreateUserView.as_view(), name='create'),
path('me/', views.ManageUserView.as_view(), name='me'),

模型.py:

class UserManager(BaseUserManager):

    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('User must have an email address.')

        user = self.model(email=self.normalize_email(email), **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user


class User(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(max_length=225, unique=True)
    name = models.CharField(max_length=225)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    objects = UserManager()
    USERNAME_FIELD = 'email'


class UserProfile(models.Model):

    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='userprofile')
    picture = models.ImageField(null=True, blank=True, upload_to=image_file_path)
    bio = models.CharField(max_length=225, blank=True)
    dob = models.DateField()
    created_on = models.DateTimeField(auto_now_add=True)

    def name(self, value):
        self.user.name = value
        self.user.save()

    def email(self, value):
        self.user.email = value
        self.user.save()

    def __str__(self):
        return self.user.email

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

Views.py:

class CreateUserView(generics.CreateAPIView):
    serializer_class = UserSerializer


class ManageUserView(generics.RetrieveUpdateAPIView):

    serializer_class = UserSerializer
    authentication_classes = (JWTAuthentication, )
    permission_classes = [permissions.IsAuthenticated]

    def get_object(self):
        return self.request.user

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)

序列化器.py:

class UserProfileSerializer(serializers.ModelSerializer):

    class Meta:
        model = UserProfile
        fields =  ['picture', 'bio', 'dob']


class UserSerializer(serializers.ModelSerializer):

    profile = UserProfileSerializer(source="userprofile", many=False)

    class Meta:
        model = get_user_model()
        fields = ['name', 'email', 'password', 'profile']
        extra_kwargs = {'password': {'write_only': True, 'min_length': 5}}

    def get_token(self, obj):
        token = RefreshToken.for_user(obj)
        return str(token.access_token)

    def create(self, validated_data):
        return get_user_model().objects.create_user(**validated_data)

    def update(self, instance, validated_data):

        password = validated_data.pop('password', None)
        if password:
            instance.set_password(password)
            instance.save()

        profile_data = validated_data.pop('profile', None)
        if profile_data is not None:
            instance.profile.picture = profile_data['picture']
            instance.profile.bio = profile_data['bio']
            instance.profile.dob = profile_data['dob']           
            instance.profile.save()
        return super().update(instance, validated_data)

    def get_name(self, obj):
        return obj.name

    def get_id(self, obj):
        return obj.id

预先感谢您的协助!

django django-models django-rest-framework django-users django-tests
1个回答
0
投票

我怀疑这两个错误是相关的。当您应该传递 JSON 字符串时,您正在传递一个 python 对象,例如,

res = self.client.post(CREATE_USER_URL, payload, content_type='application/json')

您需要将

payload
转换为正确的格式才能正常工作。

import json
...
payload_json = json.dumps(payload)
res = self.client.post(CREATE_USER_URL, payload_json, content_type='application/json')
© www.soinside.com 2019 - 2024. All rights reserved.