使用django-rest-framework我使用序列化程序使用many = True,检查已存在的项目并使其无效。
问题是:
当请求的一部分无效时,将拒绝整个请求而不创建有效对象。
示例有效负载:
[{'record_timestamp': '2016-03-04T09:46:04', 'reader_serial': u'00000000f9b320ac', 'card_serial': u'048EC71A0F3382', 'gps_latitude': None, 'gps_longitude': None, 'salt': 34, 'reader_record_id': 1063},
{'record_timestamp': '2016-03-04T09:46:06', 'reader_serial': u'00000000f9b320ac', 'card_serial': u'04614B1A0F3382', 'gps_latitude': None, 'gps_longitude': None, 'salt': 34, 'reader_record_id': 1064}]
示例回复:
[{"last_record_id":[2384],"error":["This record already exists"]},{}]
理想的回应:
[{"last_record_id":[2384],"error":["This record already exists"]},{'reader': 10, 'card': 12, 'gps_latitude': None, 'gps_longitude': None, 'reader_record_id': 1064}}]
我喜欢提供错误的第一条记录,但第二条记录要正确创建,响应是创建的对象。
class CardRecordInputSerializer(serializers.ModelSerializer):
class Meta:
model = CardRecord
fields = ('card', 'reader', 'bus', 'park', 'company', 'client',
'record_timestamp', 'reader_record_id')
read_only_fields = ('card', 'reader', 'bus', 'park', 'company'
'client')
def validate(self, data):
"""
Check that the record is unique
"""
#import ipdb; ipdb.set_trace()
hash_value = data.get("hash_value", None)
if CardRecord.objects.filter(hash_value=hash_value):
raise ValidationError(
detail={"error":"This record already exists",
"last_record_id":data.get("reader_record_id", None)})
else:
return data
def to_internal_value(self, data):
internal_value = super(CardRecordInputSerializer, self)\
.to_internal_value(data)
card_serial = data.get("card_serial", None).upper()
reader_serial = data.get('reader_serial', None).upper()
record_timestamp = data.get('record_timestamp', None)
date_altered = False
record_date = dateutil.parser.parse(record_timestamp)
#check if clock has reset to 1970
if record_date < datetime.datetime(2014, 4, 24):
record_date = datetime.datetime.now().isoformat()
date_altered = True
#create a hash to check that this record is unique
salt = data.get('salt', None)
hash_generator = hashlib.sha1()
hash_generator.update(card_serial)
hash_generator.update(reader_serial)
hash_generator.update(str(record_timestamp))
hash_generator.update(str(salt))
hash_value = str(hash_generator.hexdigest())
internal_value.update({
"card_serial": card_serial,
"reader_serial": reader_serial,
"salt": salt,
"hash_value": hash_value,
"record_timestamp": record_date,
"date_altered": date_altered
})
return internal_value
def create(self, validated_data):
#import ipdb; ipdb.set_trace()
'''
Create a new card transaction record
'''
try:
card_serial = validated_data.get('card_serial', None)
card = Card.objects.filter(uid=card_serial).last()
reader_serial = validated_data.get('reader_serial', None)
reader = Reader.objects.filter(serial=reader_serial).last()
#if we havent seen this reader before, add it to the list
if not reader:
reader = Reader.objects.create(serial=reader_serial)
company = card.company
client = reader.client
park = reader.park
record_timestamp = validated_data.get('record_timestamp', None)
reader_record_id = validated_data.get('reader_record_id', None)
#if datetime is naive, set it to utc
if record_timestamp.tzinfo is None \
or record_timestamp.tzinfo.utcoffset(d) is None:
record_timestamp = pytz.utc.localize(record_timestamp)
hash_value = validated_data.get('hash_value', None)
date_altered = validated_data.get('date_altered', None)
return CardRecord.objects.create(card = card,
reader = reader,
company = company,
client = client,
park = park,
record_timestamp = record_timestamp,
reader_record_id = reader_record_id,
hash_value = hash_value,
date_altered = date_altered)
#Usually a card that doesn't have company
except AttributeError:
return {
'status': 'Bad Request',
'message': 'One of the values was malformed or does not exist.'
}
如何创建有效对象并为无效对象提供错误?
答案 0 :(得分:0)
我最终跳过了验证。 然后在我的create方法中,如果对象已经存在,我只返回它,如果它不存在,我创建并返回它。
客户端不再知道服务器有该记录,但这对我的用例来说很好。
我还交换使用PUT来反映该方法是幂等的。
我觉得验证器是进行检查的地方,但这很有效。
class CardRecordInputSerializer(serializers.ModelSerializer):
class Meta:
model = CardRecord
fields = ('card', 'reader', 'bus', 'park', 'company', 'client',
'record_timestamp', 'reader_record_id')
read_only_fields = ('card', 'reader', 'bus', 'park', 'company'
'client')
def validate(self, data):
"""
Check that the record is unique
"""
#import ipdb; ipdb.set_trace()
#<--------Removed the validation
return data
def to_internal_value(self, data):
internal_value = super(CardRecordInputSerializer, self)\
.to_internal_value(data)
card_serial = data.get("card_serial", None).upper()
reader_serial = data.get('reader_serial', None).upper()
record_timestamp = data.get('record_timestamp', None)
date_altered = False
record_date = dateutil.parser.parse(record_timestamp)
#check if clock has reset to 1970
if record_date < datetime.datetime(2014, 4, 24):
record_date = datetime.datetime.now().isoformat()
date_altered = True
#create a hash to check that this record is unique
salt = data.get('salt', None)
hash_generator = hashlib.sha1()
hash_generator.update(card_serial)
hash_generator.update(reader_serial)
hash_generator.update(str(record_timestamp))
hash_generator.update(str(salt))
hash_value = str(hash_generator.hexdigest())
internal_value.update({
"card_serial": card_serial,
"reader_serial": reader_serial,
"salt": salt,
"hash_value": hash_value,
"record_timestamp": record_date,
"date_altered": date_altered
})
return internal_value
def create(self, validated_data):
#import ipdb; ipdb.set_trace()
'''
Create a new card transaction record
'''
try:
card_serial = validated_data.get('card_serial', None)
card = Card.objects.filter(uid=card_serial).last()
reader_serial = validated_data.get('reader_serial', None)
reader = Reader.objects.filter(serial=reader_serial).last()
#if we havent seen this reader before, add it to the list
if not reader:
reader = Reader.objects.create(serial=reader_serial)
company = card.company
client = reader.client
park = reader.park
record_timestamp = validated_data.get('record_timestamp', None)
reader_record_id = validated_data.get('reader_record_id', None)
#if datetime is naive, set it to utc
if record_timestamp.tzinfo is None \
or record_timestamp.tzinfo.utcoffset(d) is None:
record_timestamp = pytz.utc.localize(record_timestamp)
hash_value = validated_data.get('hash_value', None)
date_altered = validated_data.get('date_altered', None)
record = CardRecord.objects.filter(hash_value=hash_value).last()
if record: #<--------Check if that object already exists
return record #<-------- if it does just return it
else: #<-------- otherwise make it
return CardRecord.objects.create(
card = card,
reader = reader,
company = company,
client = client,
park = park,
record_timestamp = record_timestamp,
reader_record_id = reader_record_id,
hash_value = hash_value,
date_altered = date_altered)
#Usually a card that doesn't have company
except AttributeError:
return {
'status': 'Bad Request',
'message': 'One of the values was malformed or does not exist.'
}