Как обновить модель с помощью 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 за кулисами, но ее концептуальное представление может быть полезным.

Вернуться на верх