Oussama Eddahri
Oussama Eddahri

Reputation: 141

How to update a model with ManytoMany / ForeignKey in Django

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

Upvotes: 1

Views: 817

Answers (2)

nigel222
nigel222

Reputation: 8192

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.

Upvotes: 1

B.Anup
B.Anup

Reputation: 585

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')

Upvotes: 0

Related Questions