Python 3.x 如何将必填字段添加到我没有编写的模型中?

Python 3.x 如何将必填字段添加到我没有编写的模型中?,python-3.x,django,django-models,django-rest-framework,django-validation,Python 3.x,Django,Django Models,Django Rest Framework,Django Validation,我正在使用Django 3、Python 3.7和Django地址模块-。我想指出局部性模型的State字段是必需的。因为我自己没有写模型,所以我不太确定该怎么做。我创建了下面的序列化程序 class AddressTypeField(serializers.PrimaryKeyRelatedField): queryset = Address.objects def to_internal_value(self, data): if type(data) =

我正在使用Django 3、Python 3.7和Django地址模块-。我想指出局部性模型的State字段是必需的。因为我自己没有写模型,所以我不太确定该怎么做。我创建了下面的序列化程序

class AddressTypeField(serializers.PrimaryKeyRelatedField):

    queryset = Address.objects

    def to_internal_value(self, data):
        if type(data) == dict:
            locality = data['locality']
            state = None if not re.match(r"[0-9]+", str(locality['state'])) else State.objects.get(pk=locality['state']) 
            locality['state'] = state
            locality, created = Locality.objects.get_or_create(**locality)
            data['locality'] = locality
            address = Address.objects.create(**data)
            # Replace the dict with the ID of the newly obtained object
            data = address.pk
        return super().to_internal_value(data)
...

class CoopSerializer(serializers.ModelSerializer):
    types = CoopTypeSerializer(many=True, allow_empty=False)
    addresses = AddressTypeField(many=True)
    phone = ContactMethodPhoneSerializer()
    email = ContactMethodEmailSerializer()

    class Meta:
        model = Coop
        fields = '__all__'

    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)
        instance.phone = ContactMethod.objects.create(type=ContactMethod.ContactTypes.PHONE, **phone)
        instance.email = ContactMethod.objects.create(type=ContactMethod.ContactTypes.EMAIL, **email)
        instance.save()
        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)
        phone = validated_data.pop('phone', {})
        email = validated_data.pop('email', {})
        instance.phone = ContactMethod.objects.create(type=ContactMethod.ContactTypes.PHONE, **phone)
        instance.email = ContactMethod.objects.create(type=ContactMethod.ContactTypes.EMAIL, **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
但当我通过下面的序列化程序运行测试时

@pytest.mark.django_db
def test_coop_create_with_no_state(self):
    """ Test coop serizlizer model """
    name = "Test 8899"
    coop_type_name = "Library"
    street = "222 W. Merchandise Mart Plaza, Suite 1212"
    city = "Chicago"
    postal_code = "60654"
    enabled = True
    postal_code = "60654"
    email = "test@example.com"
    phone = "7739441422"
    web_site = "http://www.1871.com"
    serializer_data = {
        "name": name,
        "types": [
            {"name": coop_type_name}
        ],
        "addresses": [{
            "formatted": street,
            "locality": {
                "name": city,
                "postal_code": postal_code,
                "state": ''
            }
        }],
        "enabled": enabled,
        "phone": {
          "phone": phone
        },
        "email": {
          "email": email
        },
        "web_site": web_site
    }

    serializer = CoopSerializer(data=serializer_data)
    assert not serializer.is_valid()
    assert len(serializer.errors.keys()) == 1
    assert serializer.errors['phone']['phone'][0].code == "invalid_phone_number"
它会导致错误,而不是创建验证错误

Traceback (most recent call last):
  File "/Users/davea/Documents/workspace/chicommons/maps/web/tests/test_serializers.py", line 142, in test_coop_create_with_no_state
    assert not serializer.is_valid()
  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 33, 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")
如果我无法控制模型代码,如何向模型中添加必填字段?

检查AddressTypeField字段中的状态emptynes,如下所示:

class AddressTypeField(serializers.PrimaryKeyRelatedField):
    queryset = Address.objects

    def to_internal_value(self, data):
        if type(data) == dict:
            locality = data['locality']
            state = None if not re.match(r"[0-9]+", str(locality['state'])) else State.objects.get(pk=locality['state'])

            if not state:
                raise serializers.ValidationError({'state': 'This field is required.'})

            locality['state'] = state
            locality, created = Locality.objects.get_or_create(**locality)
            data['locality'] = locality
            address = Address.objects.create(**data)
            # Replace the dict with the ID of the newly obtained object
            data = address.pk
        return super().to_internal_value(data)

默认情况下,django提供了一个用户字段,其中包含email not required,如果您想将其设置为required,或者您想更改未编写的模型,您可以这样做

将此放置在任何型号的.py中

from django.contrib.auth.models import User
User._meta.get_field('email').blank = False
Then run makemigrations. Then run migrate.

完成了

我想指出局部模型的State字段是必需的,错误列State_id不能为null;默认情况下,它是必需的,并且在序列化程序_数据中,状态中的数据丢失,这就是为什么它提供IntegrityError。您是否希望将其设置为可选?如果需要状态字段,验证是否应该返回错误,而不是尝试将实体保存到数据库中?是的,将assert not serializer.is_valid更改为assert serializer.is_valid将给出AssertionError。现在它让它执行下一行;assert not False为assert True。如果您坚持在try And except AssertionError中使用assert-fit-it,那么这种方法将更简单、更可读。出于某种原因,验证似乎调用了AddressTypeField的to_internal_value方法,这最终会产生错误。我认为我需要保持该方法的原样,以便成功创建与序列化程序的协作,但它似乎干扰了验证。您应该将内容保存在save而不是in to_internal_value中。如果后面的字段拒绝验证,那么重影位置在数据库中做什么?看看如何做得更好。谢谢。是否有一个更现成的解决方案,我可以利用?似乎我应该能够在某个地方指定一个blank=False或empty=False之类的值。如果没有重写to\u internal\u值,这是可能的。。。方法如果我们看看你的代码库,状态是由一些神奇的逻辑决定的,我不认为有更好的方法来替换逻辑,因为我不理解逻辑:P