使用预先存在的对象在Django Rest Framework中创建嵌套序列化程序的问题

时间:2017-08-17 18:05:38

标签: python django serialization django-rest-framework

我无法弄清楚导致这种情况的原因。我正在从this original question开始一个新问题,因为我有一些新形成的问题。

我想让一个嵌套的序列化程序在POST请求中接受这个JSON并保存它:

{
    "id": 1,
    "sender": {
        "id": 2,
        "name": "anotherUser",
        "email": "anotherUser@email.com"
    },
    "recipients": [{
        "id": 1,
        "name": "aUser",
        "email": "user@email.com"
    }],
    "subject": "asdf",
    "body": "asdf",
    "read": false
}

所以这是我的 Serializers.py

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'name', 'email')
        extra_kwargs = {
            'id': {
                'validators': [UnicodeUsernameValidator()],
            }
        }



class MessageSerializer(serializers.ModelSerializer):
    sender = UserSerializer(read_only=True)
    recipients = UserSerializer(many=True,read_only=True)



    class Meta:
        model = Message
        fields = ('id', 'subject', 'body', 'read', 'sender', 'recipients')


    def create(self, validated_data):
        sender_data = validated_data.pop('sender')
        recipient_data = validated_data.pop('recipients')
        message = Message.objects.create(**validated_data)

        for user in recipient_data:
            user= User.objects.get(id=user['id'])
            message.recipients.save(user)

        for user in sender_data:
            user= User.objects.get(id=user['id'])
            message.sender.save(user)
        return message

这是我的 Models.py

class User(models.Model):
    # TODO Make user idNum a UUIDField
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=30)
    email = models.CharField(max_length=75)

    def __str__(self):
        return self.name


class Message(models.Model):
    # TODO make message id a UUIDField
    id = models.IntegerField(primary_key=True)
    subject = models.CharField(max_length=250)
    body = models.CharField(max_length=5000)
    read = models.BooleanField(default=False)
    sender = models.ForeignKey(User, related_name='message_sender', null=True, blank=True)
    # TODO create many to one relationship between recipients and messages
    recipients = models.ForeignKey(User, related_name='message_recip', null=True, blank=True)

使用此代码,我在/ sender / on'sender'上收到了一个Keyerror。而且我知道为什么我会得到这个!这是因为Sender ForeignKey没有得到验证。哦,那好吧。也许这是由于发送者的序列化器声明的read_only参数(它是)。

所以,我从声明中取出了read_only参数,所以它现在看起来像这样:

class MessageSerializer(serializers.ModelSerializer):

sender = UserSerializer()
recipients = UserSerializer(many=True)

这将解决验证问题。但是,我现在在/ messages /'Nonetype'对象中看到一个AttributeError没有属性'save'。这是追溯:

追溯:

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  489.             response = self.handle_exception(exc)

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception
  449.             self.raise_uncaught_exception(exc)

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  486.             response = handler(request, *args, **kwargs)

File "/Users/kevinyoung/PycharmProjects/AbstractPlay/accounts/views.py" in post
  21.             serializer.save()

File "/Users/kevinyoung/AbstractPlayEnv/lib/python3.6/site-packages/rest_framework/serializers.py" in save
  215.             self.instance = self.create(validated_data)

File "/Users/kevinyoung/PycharmProjects/AbstractPlay/accounts/serializers.py" in create
  33.             message.recipients.save(user)

Exception Type: AttributeError at /messages/
Exception Value: 'NoneType' object has no attribute 'save'
Request information:
USER: AnonymousUser

GET: No GET data

POST: No POST data

FILES: No FILES data

COOKIES: No cookie data

所以我开始调试并注意到行

user= User.objects.get(id=user['id'])

用户设置为“< accounts.models.DoesNotExist>”

好的,这是有道理的,它回来的用户实际上并不是用户......有趣。我仔细看了一下docs,我想也许它是我想要的可写序列化器,即使我不想在发送消息时创建新用户,也许我可以操纵它。

因此,我尝试将“获取”用户对象的行更改为创建新用户对象,而不是使用存储在用户变量中的有序dict,如下所示:

user= User.objects.get(id=user['id'])

现在我在user.id上得到了一个UniqueConstraint错误

这是有道理的,我试图创建一个具有相同唯一ID的新用户。我的问题是,我只是不知道从哪里开始。我觉得它与我的用户模型上的 str 方法有关吗?但我的改变似乎没有帮助。

1 个答案:

答案 0 :(得分:0)

第一

    extra_kwargs = {
        'id': {
            'validators': [UnicodeUsernameValidator()],
        }
    }

看起来很奇怪,为什么id需要验证?

其次,最重要的是,您似乎想要获取消息列表,但您的追溯显示您正在调用create
您没有向我们展示您的/messages终点应该是什么样子。

我的猜测是你不是GET -ing而是POST端点。

第三,recipients = models.ForeignKey(User, related_name='message_recip', null=True, blank=True)不会给你收件人列表但只有一个。

第四message.recipients.save(user)没有意义 您想要的可能是message.recipients = user; user.save()

总而言之,您的代码显示您在这么多事情上遇到错误。我建议你打破你想要的东西,立刻完成每一步。

您可以开始获取邮件列表,但仅限标题'