python-3.x - 如何配置我的 Django 序列化程序以在其错误数组中返回验证错误,而不是引发异常?
问题描述
我将 Django 3.0 与 Python 3.7 和 Django rest 框架一起使用。我想测试我的一个序列化程序(下面的代码),所以我编写了这个测试。请注意,我故意希望某些字段无效以测试错误消息...
@pytest.mark.django_db
def test_coop_create_with_incomplete_data(self):
""" Test coop serizlizer model """
phone = "7731112222"
serializer_data = {
"name": "",
"types": [
],
"addresses": [{
"formatted": "",
"locality": {
"name": "",
"postal_code": "",
"state": ""
}
}],
"enabled": "true",
"phone": {
"phone": phone
},
"email": {
"email": ""
},
"web_site": ""
}
serializer = CoopSerializer(data=serializer_data)
serializer.is_valid(raise_exception=False)
print(serializer.errors)
print("=================\n\n\n")
但不是在“.errors()”函数中返回错误,而是“is_valid”在下面抛出异常,
File "/Users/davea/Documents/workspace/chicommons/maps/web/tests/test_serializers.py", line 132, in test_coop_create_with_incomplete_data
serializer.is_valid(raise_exception=False)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/rest_framework/serializers.py", line 234, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/rest_framework/serializers.py", line 433, in run_validation
value = self.to_internal_value(data)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/rest_framework/serializers.py", line 490, in to_internal_value
validated_value = field.run_validation(primitive_value)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/rest_framework/fields.py", line 565, in run_validation
value = self.to_internal_value(data)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/rest_framework/relations.py", line 519, in to_internal_value
return [
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/rest_framework/relations.py", line 520, in <listcomp>
self.child_relation.to_internal_value(item)
File "/Users/davea/Documents/workspace/chicommons/maps/web/directory/serializers.py", line 31, in to_internal_value
locality, created = Locality.objects.get_or_create(**locality)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/query.py", line 562, in get_or_create
return self._create_object_from_params(kwargs, params)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/query.py", line 604, in _create_object_from_params
raise e
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/query.py", line 596, in _create_object_from_params
obj = self.create(**params)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/query.py", line 433, in create
obj.save(force_insert=True, using=self.db)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 745, in save
self.save_base(using=using, force_insert=force_insert,
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 782, in save_base
updated = self._save_table(
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 886, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/base.py", line 923, in _do_insert
return manager._insert(
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/query.py", line 1204, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1377, in execute_sql
cursor.execute(sql, params)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/backends/mysql/base.py", line 74, in execute
return self.cursor.execute(query, args)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/cursors.py", line 170, in execute
result = self._query(query)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/cursors.py", line 328, in _query
conn.query(q)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/connections.py", line 517, in query
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/connections.py", line 732, in _read_query_result
result.read()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/connections.py", line 1075, in read
first_packet = self.connection._read_packet()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/connections.py", line 684, in _read_packet
packet.check_error()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/protocol.py", line 220, in check_error
err.raise_mysql_exception(self._data)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pymysql/err.py", line 109, in raise_mysql_exception
raise errorclass(errno, errval)
django.db.utils.IntegrityError: (1048, "Column 'state_id' cannot be null")
如何配置序列化程序以返回异常,以便我可以检查它们而不是抛出异常并停止执行?显然“raise_exception=False”并没有起到作用。
下面是我的模型,引用了DJango地址包——https: //github.com/furious-luke/django-address
class Coop(models.Model):
objects = CoopManager()
name = models.CharField(max_length=250, null=False)
types = models.ManyToManyField(CoopType)
addresses = models.ManyToManyField(Address)
enabled = models.BooleanField(default=True, null=False)
phone = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_phone')
email = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_email')
web_site = models.TextField()
这是相关的序列化程序...
class CoopSerializer(serializers.ModelSerializer):
types = CoopTypeSerializer(many=True)
addresses = AddressTypeField(many=True)
phone = ContactMethodPhoneSerializer()
email = ContactMethodEmailSerializer()
class Meta:
model = Coop
fields = ['id', 'name', 'types', 'addresses', 'phone', 'enabled', 'email', 'web_site']
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['types'] = CoopTypeSerializer(instance.types.all(), many=True).data
rep['addresses'] = AddressSerializer(instance.addresses.all(), many=True).data
return rep
def create(self, validated_data):
#"""
#Create and return a new `Snippet` instance, given the validated data.
#"""
coop_types = validated_data.pop('types', {})
phone = validated_data.pop('phone', {})
email = validated_data.pop('email', {})
instance = super().create(validated_data)
for item in coop_types:
coop_type, _ = CoopType.objects.get_or_create(name=item['name'])
instance.types.add(coop_type)
print("phone:",phone)
instance.phone = ContactMethod.objects.create(type=ContactMethod.ContactTypes.PHONE, **phone)
instance.email = ContactMethod.objects.create(type=ContactMethod.ContactTypes.EMAIL, **email)
return instance
def update(self, instance, validated_data):
"""
Update and return an existing `Coop` instance, given the validated data.
"""
instance.name = validated_data.get('name', instance.name)
try:
coop_types = validated_data['types']
instance.types.clear() # Disassociates all CoopTypes from instance.
for item in coop_types:
coop_type, _ = CoopType.objects.get_or_create(**item)
instance.types.add(coop_type)
except KeyError:
pass
instance.addresses = validated_data.get('addresses', instance.addresses)
instance.enabled = validated_data.get('enabled', instance.enabled)
instance.phone = validated_data.get('phone', instance.phone)
instance.email = validated_data.get('email', instance.email)
instance.web_site = validated_data.get('web_site', instance.web_site)
instance.web_site = validated_data.get('web_site', instance.web_site)
instance.save()
return instance
class AddressSerializer(serializers.ModelSerializer):
locality = LocalityTypeField()
class Meta:
model = Address
fields = ['id', 'street_number', 'route', 'raw', 'formatted', 'latitude', 'longitude', 'locality']
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['locality'] = LocalitySerializer(instance.locality).data
return rep
def create(self, validated_data):
"""
Create and return a new `AddressField` instance, given the validated data.
"""
address = AddressTypeField.objects.create(**validated_data)
return address
def update(self, instance, validated_data):
"""
Update and return an existing `AddresssField` instance, given the validated data.
"""
instance.street_number = validated_data.get('street_number', instance.name)
instance.route = validated_data.get('route', instance.name)
instance.raw = validated_data.get('raw', instance.name)
instance.formatted = validated_data.get('formatted', instance.name)
instance.latitude = validated_data.get('latitude', instance.name)
instance.longitude = validated_data.get('longitude', instance.name)
instance.locality = validated_data.get('locality', instance.name)
instance.save()
return instance
class LocalitySerializer(serializers.ModelSerializer):
class Meta:
model = Locality
fields = ['id', 'name', 'postal_code', 'state']
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['state'] = StateSerializer(instance.state).data
return rep
def create(self, validated_data):
"""
Create and return a new `Locality` instance, given the validated data.
"""
return Locality.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
Update and return an existing `Locality` instance, given the validated data.
"""
instance.name = validated_data.get('name', instance.name)
instance.postal_code = validated_data.get('postal_code', instance.name)
instance.state = validated_data.get('state', instance.name)
instance.save()
return instance
解决方案
您可以添加if
else
您的serializer.is_valid()
然后打印serializer.errors()
.
像这样的东西:
serializer = CoopSerializer(data=serializer_data)
if serializer.is_valid():
# DO SOMETHING HERE OR PRINT
print("works")
else:
print(serializer.errors)
print("=================\n\n\n")
推荐阅读
- slack-api - 为什么 Slack 的 files.list 端点返回一个空的 files 数组?
- spring-cloud-stream - 使用 Spring Cloud DataFlow Streams 将“桶”同步到本地目录时出现问题
- python - DynamoDB 未收到整个 SQS 消息正文
- javascript - 关于 Next.js 的服务器错误的更有用的堆栈跟踪?
- python - 在 Keras 中从 .hdf5 加载模型权重时出错
- postgresql - 使用 crunchydata postgres 运算符部署自定义映像时出错
- sql - SQL Server 2019 ProgrammingError:“AUTO_INCREMENT”附近的语法不正确
- tableau-api - 计算不同年份的滚动平均值,同时显示按年份划分的数据
- math - 找到截断值的极限是什么意思?
- c++ - 两个可移动的 QGraphicsRectItem 之间的 QGraphicsPathItem