Django Serializer сохраняет объект дважды
У меня есть база данных с песнями. У каждой песни есть главный исполнитель, а все остальные исполнители перечислены в M2M как исполнители.
Я потребляю данные через API следующим образом:
def populate_song(uuid):
full_endpoint = settings.API_HOST + settings.GET_SONG_BY_ID + uuid
headers = {
'x-app-id': APP_ID,
'x-api-key': API_KEY,
}
r = requests.get(full_endpoint, headers=headers)
# Create Python object from JSON string.
if 'object' in r.json():
try:
song = r.json()['object']
song['duplicate'] = False
existingsong = Song.objects.filter(uuid=song['uuid']).first()
if existingsong:
data = SongSerializer(existingsong, data=song)
else:
data = SongSerializer(data=song)
data.is_valid(raise_exception=True)
return data.save()
except Exception as err:
print('Error saving the song with ID:' + uuid)
print(Exception, err)
if 'errors' in r.json():
# if Song is not found or is giving an error, mark this in the DB as duplicate.
Song.objects.filter(uuid=uuid).update(duplicate=True)
return
Это сериализатор для песни:
class SongSerializer(serializers.ModelSerializer):
artists = ArtistSerializer(many=True, required=False)
mainartist = ArtistSerializer(many=True, required=False)
def create(self, validated_data):
artists_data = validated_data.pop('artists', None)
# AT THIS POINT THE ERROR BREAKS THE CODE
song = Song.objects.create(**validated_data)
for artist_data in artists_data:
artist = Artist.objects.filter(uuid=artist_data.get('uuid')).first()
if not artist:
artist = Artist.objects.create(**artist_data)
if not song.mainartist:
song.mainartist = artist # populate mainartist with the first SC artist
continue
song.save()
continue
song.artists.add(artist)
return song
def update(self, instance, validated_data):
artists_data = validated_data.pop('artists', None)
instance.artists.clear() # clear all M2M artists
Song.objects.filter(pk=instance.id).update(**validated_data) # hack to update the object in one line of code.
for artist_data in artists_data:
artist = Artist.objects.filter(uuid=artist_data.get('uuid')).first()
if not artist:
artist = Artist.objects.create(**artist_data)
instance.save()
continue
instance.artists.add(artist)
return instance
Но я получаю следующую ошибку:
<class 'Exception'> duplicate key value violates unique constraint "core_song_pkey"
DETAIL: Key (id)=(533588) already exists.
Похоже, что код уже сохранен перед <>, но я не могу понять, почему. Я проверил в БД и объект действительно не существует до этого.
Есть идеи?
Можно ли использовать:
song = Song.objects.get_or_create
Этот метод является атомарным при условии, что база данных обеспечивает уникальность аргументов ключевых слов (см. unique или unique_together). Если поля, используемые в аргументах ключевых слов, не имеют ограничения уникальности, одновременные вызовы этого метода могут привести к вставке нескольких строк с одинаковыми параметрами