Почему django rest api framework эндпоинт ломается на тестах, но работает через Postman?
Привет, вот сами тесты:
class TestUser(APITestCase): fake = Faker() def generate_data(self): path = os.path.join(settings.MEDIA_ROOT, "test_files/climber.webp") url = reverse('upload_image') with open(path, "rb") as file: response = self.client.post(url, {"image": file}, format='multipart') self.assertEqual(response.status_code, status.HTTP_201_CREATED) photo_id = response.data.get("id") fake = Faker() return { "first_name": fake.first_name(), "last_name": fake.last_name(), "phone": fake.phone_number(), "birthday": fake.date_of_birth().strftime('%Y-%m-%d'), "weight": random.randint(50, 100), "growth": random.randint(150, 200), "photo": photo_id, "city_id": random.randint(1, 10), "rope_length": random.randint(50, 80), "quickdraws": random.randint(5, 15), "lead_indoor_climbing": random.choice([True, False]), "lead_outdoor_climbing": random.choice([True, False]), "indoor_bouldering": random.choice([True, False]) } def setUp(self): self.django_user = DjangoUser.objects.create_user(username=self.fake.user_name(), password=self.fake.password()) self.token = Token.objects.create(user=self.django_user) self.api_authentication() self.user = User.objects.create(**self.generate_data()) def api_authentication(self): self.client = APIClient() self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) def test_create_user(self): url = reverse('create_user') response = self.client.post(url, self.generate_data(), format='json') print(response.data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(User.objects.count(), 2) # self.assertEqual(User.objects.get(username='').username, 'newuser') def test_create_user_bad_request(self): url = reverse('create_user') data = self.generate_data() data["weight"] = "string" response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) |
class TestUser(APITestCase): fake = Faker() def generate_data(self): path = os.path.join(settings.MEDIA_ROOT, "test_files/climber.webp") url = reverse('upload_image') with open(path, "rb") as file: response = self.client.post(url, {"image": file}, format='multipart') self.assertEqual(response.status_code, status.HTTP_201_CREATED) photo_id = response.data.get("id") fake = Faker() return { "first_name": fake.first_name(), "last_name": fake.last_name(), "phone": fake.phone_number(), "birthday": fake.date_of_birth().strftime('%Y-%m-%d'), "weight": random.randint(50, 100), "growth": random.randint(150, 200), "photo": photo_id, "city_id": random.randint(1, 10), "rope_length": random.randint(50, 80), "quickdraws": random.randint(5, 15), "lead_indoor_climbing": random.choice([True, False]), "lead_outdoor_climbing": random.choice([True, False]), "indoor_bouldering": random.choice([True, False]) } def setUp(self): self.django_user = DjangoUser.objects.create_user(username=self.fake.user_name(), password=self.fake.password()) self.token = Token.objects.create(user=self.django_user) self.api_authentication() self.user = User.objects.create(**self.generate_data()) def api_authentication(self): self.client = APIClient() self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) def test_create_user(self): url = reverse('create_user') response = self.client.post(url, self.generate_data(), format='json') print(response.data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(User.objects.count(), 2) # self.assertEqual(User.objects.get(username='').username, 'newuser') def test_create_user_bad_request(self): url = reverse('create_user') data = self.generate_data() data["weight"] = "string" response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Получается есть отдельная модель с изображениями, а поле photo модели User - это ссылка на экземпляр модели с изображениями.
Но я ловлю ошибку:
====================================================================== ERROR: test_create_user_bad_request (finder.tests.test_setup.TestUserSetup) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/levbariakh/web/climbing_tinder/finder/tests/test_setup.py", line 46, in setUp self.user = User.objects.create(**self.generate_data()) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/manager.py", line 87, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/query.py", line 656, in create obj = self.model(**kwargs) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/base.py", line 543, in __init__ _setattr(self, field.name, rel_obj) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py", line 266, in __set__ raise ValueError( ValueError: Cannot assign "2": "User.photo" must be a "Image" instance. ---------------------------------------------------------------------- Ran 2 tests in 2.062s FAILED (errors=2) Destroying test database for alias 'default'... |
====================================================================== ERROR: test_create_user_bad_request (finder.tests.test_setup.TestUserSetup) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/levbariakh/web/climbing_tinder/finder/tests/test_setup.py", line 46, in setUp self.user = User.objects.create(**self.generate_data()) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/manager.py", line 87, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/query.py", line 656, in create obj = self.model(**kwargs) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/base.py", line 543, in __init__ _setattr(self, field.name, rel_obj) File "/Users/levbariakh/web/climbing_tinder/.venv/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py", line 266, in __set__ raise ValueError( ValueError: Cannot assign "2": "User.photo" must be a "Image" instance. ---------------------------------------------------------------------- Ran 2 tests in 2.062s FAILED (errors=2) Destroying test database for alias 'default'...
Я подумал что надо просто вручную преобразовать id в экземпляр модели Image:
class UserCreateSerializer(serializers.ModelSerializer): class Meta: model = User fields = "__all__" def create(self, validated_data): photo_id = validated_data.get('photo').id validated_data.pop("photo") try: photo = Image.objects.get(id=photo_id) except (Image.DoesNotExist, ValueError): logger.error(f"Image with id {photo_id} not found") raise serializers.ValidationError("Image not found") user = User.objects.create(photo=photo, **validated_data) return user |
class UserCreateSerializer(serializers.ModelSerializer): class Meta: model = User fields = "__all__" def create(self, validated_data): photo_id = validated_data.get('photo').id validated_data.pop("photo") try: photo = Image.objects.get(id=photo_id) except (Image.DoesNotExist, ValueError): logger.error(f"Image with id {photo_id} not found") raise serializers.ValidationError("Image not found") user = User.objects.create(photo=photo, **validated_data) return user
При этом через Postman всё работает, что делать?
Дополнительно:
через Postman ты тоже число в photo суешь?
задать кучу вопросов и так не научится ставить теги к вопросу
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Проблема, когда Django REST API framework эндпоинт ломается на тестах, но работает через Postman, может иметь несколько причин. Давайте рассмотрим возможные причины и способы их решения.
1. Различие в окружениях: Возможно, что настройки окружения для тестов отличаются от настроек, которые используются при использовании Postman. Убедитесь, что все необходимые зависимости установлены и настройки среды выполнения идентичны.
2. Аутентификация: Если ваш API требует аутентификации, убедитесь, что ваши тесты правильно передают данные аутентификации. Postman может автоматически управлять этим, в то время как ваши тесты могут не передавать необходимые заголовки или токены.
3. Неправильные данные: Проверьте, что данные, которые вы отправляете через тесты, соответствуют ожидаемому формату. Некорректные данные могут вызвать ошибку на этапе обработки запроса.
4. Обработка ошибок: Убедитесь, что ваш API обрабатывает ошибки правильно. Возможно, что ваш тест отправляет запрос, который вызывает ошибку, но API не обрабатывает эту ошибку должным образом.
Для отладки проблемы, попробуйте добавить вывод отладочной информации в ваш код API, чтобы увидеть, где именно возникает проблема. Также рекомендуется использовать инструменты для отладки API запросов, такие как curl или Postman Console, чтобы сравнить запросы, отправляемые вашими тестами и Postman.
Применяйте эти советы, чтобы идентифицировать и исправить причину проблемы с Django REST API framework эндпоинтом, который ломается на тестах, но работает через Postman.