所以后面的故事是我有一个包含3个字段的模型。一个用默认填充,另一个用API请求传入,最后一个在视图中计算。我无法弄清楚如何将request.data和计算值同时送入序列化程序。这是我的模特:
import re
from django.core.exceptions import ValidationError
from django.core.validators import URLValidator
from django.db import models
from django.utils import timezone
URL_MAX_SHORT_ID_LEN = 12
# Maximum length for IE and several other search engines and protocols is
# 2047/2048.
URL_MAX_URL_LEN = 2047
class URL(models.Model):
short_id = models.CharField(max_length=URL_MAX_SHORT_ID_LEN, primary_key=True)
url = models.URLField(max_length=URL_MAX_URL_LEN)
added_date = models.DateTimeField('date added',
default=timezone.now)
def clean(self):
# TODO: make max length and possible chars a setting or global variable
if re.match('^[a-zA-Z0-9]{1,' + str(URL_MAX_SHORT_ID_LEN) + '}$', self.short_id) is None:
raise ValidationError({'short_id':
'only a-zA-Z0-9 valid chars and max length of ' +
str(URL_MAX_SHORT_ID_LEN)
})
def save(self, *args, **kwargs):
self.full_clean()
super(URL, self).save(*args, **kwargs)
def __str__(self):
return str(self.__class__) + ': ' + str(self.__dict__)
这是我的序列化器:
from rest_framework import serializers
from url_shortener.models import URL
class URLSerializer(serializers.ModelSerializer):
short_id = serializers.SerializerMethodField()
class Meta:
model = URL
fields = ('short_id', 'url', 'added_date')
read_only_fields = ('added_date',)
def get_short_id(self, obj):
return self.context.get('short_id')
在shell中进行测试会抛出一条错误,指出short_id为空:
>>> from url_shortener.serializers import *
>>> from django.utils.six import BytesIO
>>> from rest_framework.renderers import JSONRenderer
>>> from rest_framework.parsers import JSONParser
>>>
>>> j = b'{"url":"https://gobin.io"}'
>>> stream = BytesIO(j)
>>> data = JSONParser().parse(stream)
>>> s = URLSerializer(data=data, context={'short_id': 'asd123'})
>>> s.is_valid()
True
>>> s.validated_data
OrderedDict([('url', 'https://gobin.io')])
>>> s.save()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/jolly/git/lurl/myenv/lib/python3.5/site-packages/rest_framework/serializers.py", line 215, in save
self.instance = self.create(validated_data)
File "/Users/jolly/git/lurl/myenv/lib/python3.5/site-packages/rest_framework/serializers.py", line 916, in create
instance = ModelClass.objects.create(**validated_data)
File "/Users/jolly/git/lurl/myenv/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/jolly/git/lurl/myenv/lib/python3.5/site-packages/django/db/models/query.py", line 394, in create
obj.save(force_insert=True, using=self.db)
File "/Users/jolly/git/lurl/lurl/url_shortener/models.py", line 27, in save
self.full_clean()
File "/Users/jolly/git/lurl/myenv/lib/python3.5/site-packages/django/db/models/base.py", line 1248, in full_clean
raise ValidationError(errors)
django.core.exceptions.ValidationError: {'short_id': ['This field cannot be blank.', 'only a-zA-Z0-9 valid chars and max length of 12']}
似乎get_short_id永远不会被调用。我加注了它,它从未被抛出。我不确定我做错了什么,或者这是做我正在做的事情的正确方法。
答案 0 :(得分:0)
SerializerMethodField是read only。您可以使用普通的CharField并将其值传递给序列化程序保存方法,而不是:
class URLSerializer(serializers.ModelSerializer):
short_id = serializers.CharField()
在视图中:
s = URLSerializer(data=data)
s.is_valid()
s.save(short_id='asd123')
答案 1 :(得分:0)
我终于找到了正确的搜索词,找到了similar stackoverflow。我不确定它是否总是正确的,但在我的情况下,short_id实际上是read_only。所以我用extra_kwargs创建了我的序列化器:
from rest_framework import serializers
from url_shortener.models import URL, URL_MAX_SHORT_ID_LEN
class URLSerializer(serializers.ModelSerializer):
class Meta:
model = URL
fields = ('short_id', 'url', 'added_date')
read_only_fields = ('added_date',)
extra_kwargs = {
'short_id' : {'read_only' : True}
}
然后验证并保存如下:
s = URLSerializer(data=data)
s.is_valid()
s.save(short_id='asd123')