Ho tre modelli Giocatore, squadra e appartenenza, dove giocatore e squadra hanno molti-to- molte relazioni che utilizzano l'abbonamento come modello intermedio.Come aggiornare i valori in istanza quando si dispone di un custom.update() per aggiornare le relazioni molti-a-molti in serializzatore annidato scrivibile DRF
class Player(models.Model):
name = models.CharField(max_length=254)
rating = models.FloatField(null=True)
install_ts = models.DateTimeField(auto_now_add=True, blank=True)
update_ts = models.DateTimeField(auto_now_add=True, blank=True)
class Team(models.Model):
name = models.CharField(max_length=254)
rating = models.FloatField(null=True)
players = models.ManyToManyField(
Player,
through='Membership',
through_fields=('team', 'player'))
is_active = models.BooleanField(default=True)
install_ts = models.DateTimeField(auto_now_add=True, blank=True)
update_ts = models.DateTimeField(auto_now_add=True, blank=True)
class Membership(models.Model):
team = models.ForeignKey('Team')
player = models.ForeignKey('Player')
#date_of_joining = models.DateTimeField()
install_ts = models.DateTimeField(auto_now_add=True, blank=True)
update_ts = models.DateTimeField(auto_now_add=True, blank=True)
Ora mi è stato richiesto di aggiornare questo abbonamento utilizzando il framework django rest. Ho provato ad aggiornare quelli usando Writable nested serializers scrivendo un custom .update()
di serializzatore di squadra.
@transaction.atomic
def update(self, instance, validated_data):
'''
Cutomize the update function for the serializer to update the
related_field values.
'''
if 'memberships' in validated_data:
instance = self._update_membership(instance, validated_data)
# remove memberships key from validated_data to use update method of
# base serializer class to update model fields
validated_data.pop('memberships', None)
return super(TeamSerializer, self).update(instance, validated_data)
def _update_membership(self, instance, validated_data):
'''
Update membership data for a team.
'''
memberships = self.initial_data.get('memberships')
if isinstance(membership, list) and len(memberships) >= 1:
# make a set of incoming membership
incoming_player_ids = set()
try:
for member in memberships:
incoming_player_ids.add(member['id'])
except:
raise serializers.ValidationError(
'id is required field in memberships objects.'
)
Membership.objects.filter(
team_id=instance.id
).delete()
# add merchant member mappings
Membership.objects.bulk_create(
[
Membership(
team_id=instance.id,
player_id=player
)
for player in incoming_player_ids
]
)
return instance
else:
raise serializers.ValidationError(
'memberships is not a list of objects'
)
Ora questo funziona bene per l'aggiornamento dei valori nel database per la tabella di appartenenza. L'unico problema che ho di fronte è che non sono in grado di aggiornare l'istanza prefetched nella memoria, che sulla richiesta PATCH a questa API aggiorna i valori nel database ma la risposta API mostra dati obsoleti.
La successiva richiesta di GET per la stessa risorsa fornisce dati aggiornati. Chiunque abbia lavorato con molti-a-molti in django e abbia scritto metodi di aggiornamento/creazione personalizzati per serializzatori nidificati scrivibili può aiutarmi a capire il modo possibile per risolvere questo problema.
A partire da Django 1.8 c'è una funzione integrata per [aggiornare un oggetto] (https://docs.djangoproject.com/en/1.8/ref/models/instances/#refreshing-objects-from-database). Potresti semplicemente usare 'instance.refresh_from_db()'. – AKS
Ho provato a fare ciò che non funziona con prefetch_related. –
Bene, il mio commento è stato solo per il secondo punto considerando che il primo punto è già in atto. E ancora una cosa: perché stai aggiornando i 'memberships 'da' initial_data' e non da 'validated_data' ?? Non devi usare 'memberships = validated_data.get ('memberships')' nella funzione 'update_membership'? – AKS