Как обновить модель с помощью ManytoMany / ForeignKey в Django
У меня есть модель Study, содержащая множество Targets (ManyToManyField) Каждый Target содержит Location (ForeignKey):
class Study(models.Model):
uid = models.AutoField(primary_key=True)
targets = models.ManyToManyField(Target)
class Target(models.Model):
uid = models.AutoField(primary_key=True)
location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True, blank=True )
class Localization(models.Model):
x = models.FloatField(blank=True)
В моем представлении я хочу обновить местоположение, которое находится в указанном исследовании -> Target
def update_locations(request):
data = json.loads(request.body.decode('utf-8'))
if request.method == 'POST':
study_to_update = Study.objects.get(uid = data["study"])
targets = study_to_update.targets.all()
target_to_update = [target for target in targets if target.uid == data["target"]][0]
new_location = Location(x = data["location"])
#target_to_update.remove(?)
#target_to_update.add(new_location)
study_to_update.save()
else:
return HttpResponseForbidden('Erreur dans la requéte')
Я не знаю, правильно это или нет
Насколько я понимаю, вы пытаетесь создать новый объект местоположения в модели Location и обновить этот вновь созданный объект местоположения в целевой объект, который был отфильтрован на основе data['study'] и data['target'].
def update_locations(request):
data = json.loads(request.body.decode('utf-8'))
if request.method == 'POST':
study_to_update = Study.objects.get(uid = data["study"])
targets = study_to_update.targets.all()
target_to_update = [target for target in targets if target.uid == data["target"]][0]
# new location object is created.
new_location = Location.objects.create(x=data['location'])
# since new_location can point to multiple rows of Target model, we add the 'target_to_update' into the relationship set. new_location will be in relationship with target_to_update object.
new_location.target_set.add(target_to_update)
else:
return HttpResponseForbidden('Erreur dans la requéte')
На первый взгляд, это сработает, насколько это возможно.
study_to_update.targets.all() - это кверисет, поэтому его можно искать с помощью .filter() и т.д. вместо итерации по targets_to_update:
target = study_to_update.targets.filter( uid=data["target"]).first()
if target is not None: # first() may return nothing
...
Я не совсем понимаю, что должна делать следующая часть. Чтобы обновить местоположение в target:
new_location = Location( ...)
new_location.save() # won't have a pk until saved, can't be a ForeignKey until it does
target.location = new_location
target.save() # update location
Это обновит местоположение для конкретного target объекта (строки БД), который остается в списке "многие-ко-многим" объекта исследования. Вам не нужно сохранять study_to_update.
Если вместо этого или так же, как и в случае с study.targets, вы хотите работать с study.targets.add( target_instance) или .remove( target_instance). target_instance необходимо сохранить в БД, прежде чем вы сможете его добавить.
Возможно, поможет вспомнить, что many-to-many реализуется как таблица DB с двумя ForeignKeys на строку. В данном случае один идентифицирует объект study, а другой - экземпляр target. Эта таблица управляется Django за кулисами, но ее концептуальное представление может быть полезным.