# Updating Model from form of separate Model

**URL:** <https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020>\
**Category:** Forms & APIs\
**Created:** [January 17, 2024, 12:20am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020 "2024-01-17T00:20:54Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 12:20am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/1 "2024-01-17T00:20:54Z")

</div>

Python: 3.11.5  
Django: 5.0.1

I have a form that saves one model fine (GlobalProject). In that form I have a a ModelMultipleChoiceField that pulls from a different model (Deals). When a new GlobalProject is created with selections made in that drop down, I want to update those models (the Deals) with a foreign key of the newly created GlobalProject. The models are not managing the database objects, that’s happening somewhere else and the actual database tables have more columns than are listed in the Django models.

I thought I was close but I keep getting the following error: `Save with update_fields did not affect any rows`.

Here’s my code that is generating this:

models.py

```auto
class GlobalProject(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(unique=True, max_length=300)
    is_internal = models.BooleanField(default=False) 
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__ (self) -> str:
        return str(self.name)

    class Meta:
        managed = False
        db_table = "global_projects"

class Deal(models.Model):
    id = models.IntegerField(primary_key=True, editable=False)
    amount = models.FloatField(editable=False)
    name = models.TextField(editable=False)
    is_closed_won = models.BooleanField(editable=False)
    global_project = models.ForeignKey(
        GlobalProject, on_delete=models.SET_NULL, null=True
    )

    def __str__ (self) -> str:
        return str(self.name)

    class Meta:
        managed = False
        db_table = "deals"

```

forms.py

```auto
class GlobalProjectNewForm(ModelForm):

    deal_queryset = Deal.objects.order_by("name").filter(
        is_closed_won=True, global_project=None
    )

    deal_dropdown = ModelMultipleChoiceField(
        label="Link to Closed Won Deals",
        widget=SelectMultiple(attrs={"class": "form-control"}),
        queryset=deal_queryset,
    )

    def __init__ (self, *args, **kwargs):
        super(). __init__ (*args, **kwargs)
        self.fields["deal_dropdown"].initial = self.deal_queryset.values_list(
            "name", flat=True
        )

    def save(self, commit=True):
        project = super().save(commit=commit)
        deals = self.cleaned_data["deal_dropdown"]
        for deal in deals:
            deal.global_project = project
            deal.save(update_fields=["global_project"])
        return project

    class Meta:
        model = GlobalProject
        fields = ("name", "is_internal")

```

views.py

```auto
def new(request):
    ProjectFormSet = modelform_factory(GlobalProject, form=GlobalProjectNewForm)

    if request.method == "POST":
        formset = ProjectFormSet(request.POST, request.FILES)
        if formset.is_valid():
            instance = formset.save()
            return redirect("projects:detail", project_id=instance.id)
    else:
        formset = ProjectFormSet()

    return render(request, "projects/new.html", {"formset": formset})

```

After running the above and creating a POST request, a new GlobalProject object is created in the database with corresponding UUID. The associated deals are never updated and the `deal.save()` is where the `Save with update_fields did not affect any rows` is coming from.

Any idea on how to do what I am trying to do here? Thanks!

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 12:45am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/2 "2024-01-17T00:45:01Z")

</div>

Debugged down into Django and the place it seems to fail for me is in this method. `filtered` is always an empty collection, but `base_qs` has all the rows from the Deals table in it but the filtering fails to find the row with the `pk_val` (even though it’s there in the QuerySet.) Don’t know if this is a red herring or what.

```auto
 def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_update):
        """
        Try to update the model. Return True if the model was updated (if an
        update query was done and a matching row was found in the DB).
        """
        filtered = base_qs.filter(pk=pk_val)

```

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 4:00pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/3 "2024-01-17T16:00:57Z")

</div>

Ok, maybe I’m getting somewhere by reading the docs?

I’m explicitly creating the queryset for the Deals here:

```auto
deal_queryset = Deal.objects.order_by("name").filter(
        is_closed_won=True, global_project=None
    )

```

This seems to mean that the “backend is not setup” correctly for the filters and saves to work correctly on this object? Is that correct? Is there a way to access the Deals objects, within the form that is more in the genre of “GlobalProjects” in a way I can modify the Deals objects?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 17, 2024, 5:11pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/4 "2024-01-17T17:11:06Z")

</div>

Rephrasing to ensure I understand the situation correctly.

- You have a model named “GlobalProject”.

- You have another model named “Deal”, containing an FK to “GlobalProject”.

- Your form for “GlobalProject” contains a multi-select field, populated from some set of instances of “Deal”.

- When you create a new GlobalProject, you want to update all the selected instances of Deal so that those instances now relate to this new instance of GlobalProject.

If this is all correct, then your first thing to correct here is where you’re overriding the initial values of the `deal_dropdown` field in the form. Those entries need to be populated with the 2-tuples of (pk, display) values for each `Deal` being presented, and not just the display name. See the docs for [ModelMultipleChoiceField](https://docs.djangoproject.com/en/5.0/ref/forms/fields/#modelmultiplechoicefield).

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 5:16pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/5 "2024-01-17T17:16:35Z")

</div>

Your summary is correct! Thanks, I’ll take a look at that documentation.

It’s interesting, in that the selection does come through as a “full object” (sorry not sure the correct terminology yet), in that when debugging, I can see the id, name, etc for the selected Deals. But filtering the queryset of Deals always returns nothing.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 17, 2024, 5:22pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/6 "2024-01-17T17:22:49Z")

</div>

It would be interesting to see the html for that selection box and the details of what was returned in the form, (the contents of `request.POST`), along with what the form is reporting in `self.cleaned_data['deal_dropdown']`.

Also, I know that formsets do some things differently. It’s possible that you may need to save the formset _first_, before iterating over the list of forms in the formset to save the related objects. That’s probably the first thing that I would try. (Doing this instead of trying to save the related objects in the form save method for that form.)

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 5:33pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/7 "2024-01-17T17:33:58Z")

</div>

Here is the HTML generated for the form (the selection list is a lot longer in reality, like 50 entries.)

```auto
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Add a new project</title>
</head>

<body>
<div id="content">
    <form method="post">
        <input type="hidden" name="csrfmiddlewaretoken" value="">
        <div>
            <label for="id_name">Name:</label>
            <input type="text" name="name" maxlength="300" required id="id_name">
        </div>

        <div>
            <label for="id_is_internal">Is internal:</label>
            <input type="checkbox" name="is_internal" id="id_is_internal">
        </div>

        <div>
            <label for="id_deal_dropdown">Link to Closed Won Deals:</label>

            <select name="deal_dropdown" class="form-control" required id="id_deal_dropdown" multiple>
              <option value="1">Deal Name 1</option>
              <option value="2">Deal Name 2</option>
              <option value="3">Deal Name 3</option>
            </select>
        </div>
        <button type="submit">Add</button>
    </form>
</div>
</body>
</html>

```

The value of the POST:

```auto
<QueryDict: {'csrfmiddlewaretoken': ['something'], 'name': ['A Cool Project'], 'deal_dropdown': ['2']}>

```

Which looks correct to me, I selected only 1 deal, with id = 2.

The QuerySet returned from `self.cleaned_data["deal_dropdown"]` looks correct too. It has the proper ID, proper DB, proper query for finding that one row out of the table.

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 5:37pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/8 "2024-01-17T17:37:45Z")

</div>

> [@KenWhitesell](#):
>
> Also, I know that formsets do some things differently. It’s possible that you may need to save the formset _first_, before iterating over the list of forms in the formset to save the related objects. That’s probably the first thing that I would try. (Doing this instead of trying to save the related objects in the form save method for that form.)

Hmm. I don’t have any other forms. This is my view that is kicking all this off:

```auto
def new(request):
    ProjectFormSet = modelform_factory(GlobalProject, form=GlobalProjectNewForm)

    if request.method == "POST":
        formset = ProjectFormSet(request.POST, request.FILES)
        if formset.is_valid():
            instance = formset.save()
            return redirect("projects:detail", project_id=instance.id)
    else:
        formset = ProjectFormSet()

```

Are you saying the `formset.save()` should happen, then deal with saving the Deal updates in this `new` method?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 17, 2024, 5:42pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/9 "2024-01-17T17:42:57Z")

</div>

Yes.

You have (with one line inserted):

> [@nathan-gilbert](#):
>
> ```auto
> if formset.is_valid():
> instance = formset.save()
> ***new code here***
> return redirect("projects:detail", project_id=instance.id)
> 
> ```

Remove the code from `GlobalProjectNewForm.save()` that attempts to update `Deal`.

Iterate over the forms in `instance` (the saved instances of `GlobalProject` from the formset), and for each form in `instance`, _then_ save the updated instances of `Deal`. (This would be done at the location identified by ` ***new code here*** `.)

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 11:30pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/10 "2024-01-17T23:30:37Z")

</div>

Ok, tried that, but still getting the `Save with `update\_fields` did not update any rows` Exeption.

I updated views.py like so:

```auto
    if request.method == "POST":
        formset = ProjectFormSet(request.POST, request.FILES)
        if formset.is_valid():
            instance = formset.save()
            deals = formset.cleaned_data["deal_dropdown"]
            for deal in deals:
                deal.global_project = instance
                deal.save(update_fields=["global_project"])

```

You think this could be because the `Deals` model is unmanaged? There’s a lot more columns in that table than I’m telling Django about and that’s the reason I’m trying to use the `update_fields` parameter.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 17, 2024, 11:32pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/11 "2024-01-17T23:32:49Z")

</div>

You’re iterating over the wrong objects.

You need to iterate over the forms in `instance`, and _then_ get the cleaned data from _that_ form to update the individual instances of `Deal`.

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 11:39pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/12 "2024-01-17T23:39:40Z")

</div>

I’m not sure what should be iterated over in the `instance` object? Here’s all I see on the object in the debugger:

Doesn’t appear to be a `forms` field? There should only be 1 project ever created by this form at a time if that matters.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 17, 2024, 11:54pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/13 "2024-01-17T23:54:50Z")

</div>

> [@nathan-gilbert](#):
>
> There should only be 1 project ever created by this form at a time if that matters.

What’s the purpose of the formset then? I’m not following what you’re doing here.

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 17, 2024, 11:58pm UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/14 "2024-01-17T23:58:20Z")

</div>

Good question. I actually have my variables named incorrectly. The `ProjectFormSet` variable really is a `ModelFormMetaClass` and not a FormSet type. It’s coming from the `modelform_factory` method.

I’m still learning Django, obviously. I believe I was using a Formset originally but switch at some point to the modelform.

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 18, 2024, 12:02am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/15 "2024-01-18T00:02:44Z")

</div>

Changed to this in the views.py

```auto
    if request.method == "POST":
        form = ProjectForm(request.POST, request.FILES)
        if form.is_valid():
            instance = form.save()
            selected_deals = form.cleaned_data["deal_dropdown"]
            for d in selected_deals:
                deal = Deal.objects.get(pk=d.pk)
                deal.global_project = instance
                deal.save(update_fields=["global_project"])

```

Still not saving the Deal. Gets a NotFound exception on `Deal.objects.get(pk=d.pk)`, but the `d.pk` value definitely exists in the database.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 18, 2024, 12:06am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/16 "2024-01-18T00:06:48Z")

</div>

Use your debugger or add a print statement to see what `d` and `d.pk` are at the `deal = Deal.objects.get(pk=d.pk)` line.

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 18, 2024, 12:09am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/17 "2024-01-18T00:09:16Z")

</div>

`d` is a Deal and the `pk` matches what this row has in the database.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/djangoproject/original/3X/c/c/cc9c369d92e30c94f4abcdea262976a3da77f450.png)

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 18, 2024, 12:11am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/18 "2024-01-18T00:11:56Z")

</div>

Can you post the complete traceback please?

---

<div class="post-metadata">

**Author:** ![nathan-gilbert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nathan-gilbert/32/18454_2.png) [@nathan-gilbert](https://forum.djangoproject.com/u/nathan-gilbert)\
**Post date:** [January 18, 2024, 12:13am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/19 "2024-01-18T00:13:30Z")

</div>

![image](https://us1.discourse-cdn.com/flex026/uploads/djangoproject/original/3X/0/f/0f6ff8e8a1698e7a90169a7580078fb37fb26258.png)

There’s one window’s worth of the stacktrace

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [January 18, 2024, 12:15am UTC](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020/20 "2024-01-18T00:15:19Z")

</div>

I’m sorry, I need to see the python- generated traceback with all the details included.  
I’m assuming you’re using runserver for this? You might need to run it directly from the command line to get it. (I don’t know what you’re using here.)

[Next page](https://forum.djangoproject.com/t/updating-model-from-form-of-separate-model/27020.md?page=2)
