Home > database >  How to update a model with ManytoMany / ForeignKey in Django
How to update a model with ManytoMany / ForeignKey in Django

Time:04-13

I have a model Study containing many Targets (ManyToManyField) Each Target contains a 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)

in my view I want to update the Location that is in a specified Study -> 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')

I don't know if this is right or not

CodePudding user response:

As per my understanding, you are trying to create new location object in Location model and update this newly created location object into target object, which was filtered based on data['study'] and 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')

CodePudding user response:

At a glance, that will work as far as it goes.

study_to_update.targets.all() is a queryset, so you can search it using .filter() etc. instead of iterating through targets_to_update:

target = study_to_update.targets.filter( uid=data["target"]).first()

if target is not None:   # first() may return nothing
    ...

I don't fully understand what the next part is supposed to do. To update the location in 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

This will update the location for a particular target object (DB row) which remains in the study object's many-to-many list. You don't need to save study_to_update.

If instead or as well you want to operate on study.targets you would use study.targets.add( target_instance) or .remove( target_instance). target_instance needs to be saved to the DB before you can add it.

It may help to remember that many-to-many is implemented as a DB table with two ForeignKeys per row. In this case one identifies a study object and the identifies a target instance. This table is managed by Django behind the scenes, but conceptualizing it may be useful.

  • Related