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.