# Django CRUD functionality with 2 models

**URL:** <https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323>\
**Category:** Forms & APIs\
**Created:** [June 16, 2022, 4:18pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323 "2022-06-16T16:18:09Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 16, 2022, 4:18pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/1 "2022-06-16T16:18:09Z")

</div>

I was building the CRUD-functionality with `create_project_old`, `update_project`, `delete_project`. Then I slightly switched my models.py and `create_project_new` view but I unfortunately do not really know how I have to change my `update_project` and `delete_project` views now. In addition I have to add the “user-related-part” in `create_project_new`. I have also posted my new models.py and forms.py. Thanks!

views.py

```auto
def create_project_new(request):
    form = ProjectForm()
    form2 = ProjectImageForm()

    if request.method == 'POST':
        form = ProjectForm(request.POST)
        form2 = ProjectImageForm(request.POST, request.FILES)
        images = request.FILES.getlist('image')
        if form.is_valid() and form2.is_valid():
            title = form.cleaned_data['title']
            describ = form.cleaned_data['describtion']
            price = form.cleaned_data['price']
            project_instance = Project.objects.create(
                title=title, describtion=describ, price=price)
            print(project_instance)

            for i in images:
                ProjectImage.objects.create(project=project_instance, image=i)
            return redirect('projects')

    context = {'form': form, 'form2': form2}
    return render(request, 'projects/project_form.html', context)

def create_project_old(request):
    profile = request.user.profile
    form = ProjectForm()

    if request.method == 'POST':
        form = ProjectForm(request.POST, request.FILES)
        if form.is_valid():
            project = form.save(commit=False)
            project.owner = profile
            project.save()
            return redirect('account')

    context = {'form':form}
    return render(request, 'projects/project_form.html', context)

@login_required(login_url='login')
def update_project(request, pk):
    profile = request.user.profile
    project = profile.project_set.get(id=pk)
    form = ProjectForm(instance=project)

    if request.method == 'POST':
        form = ProjectForm(request.POST, request.FILES, instance=project)
        if form.is_valid():
            form.save()
            return redirect('projects')

    context = {'form':form}
    return render(request, 'projects/project_form.html', context)

@login_required(login_url='login')
def deleteProject(request, pk):
    profile = request.user.profile
    project = profile.project_set.get(id=pk)
    if request.method == "POST":
        project.delete()
        return redirect('account')
    context = {'object':project}
    return render(request, 'delete_template.html', context)

```

models.py

```auto
class Project(models.Model):
    owner = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    describtion = models.TextField(null=True, blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2, default=10)
    id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)

    def __str__ (self):
        return self.title

class ProjectImage(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    image = models.FileField(upload_to="products/")
    
    def __str__ (self):
        return self.image

```

forms.py

```auto
class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ['title', 'describtion', 'price']

class ProjectImageForm(forms.ModelForm):
    class Meta:
        model = ProjectImage
        fields = ['image']
        widgets = {
            'image': ClearableFileInput(attrs={'multiple': True}),
        }

```

---

<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:** [June 16, 2022, 4:29pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/2 "2022-06-16T16:29:38Z")

</div>

What is the new behavior that you are looking to implement in your `update_project` and `delete_project` views?

Also, you ask:

> [@PhilEXverse](#):
>
> In addition I have to add the “user-related-part” in `create_project_new`.

Why do you think that would be different from how you’ve done it in your `create_project_old`? Has the requirement changed for it?

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 16, 2022, 5:24pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/3 "2022-06-16T17:24:59Z")

</div>

In my old models.py I had just one model. But I´ve made it possible to let the user upload multiple images. Therefore I´ve created two models and changed `create_project_old` to `create_project_new`. That´s the whole new behavior. I just do not know what I have to change in those three views.  
No further requirements changed from the previous ones.

---

<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:** [June 16, 2022, 5:33pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/4 "2022-06-16T17:33:29Z")

</div>

Ok, let’s approach these one-at-a-time to try and avoid confusion among them. Since you’re already showing a `create_project_new` method, that might be the best one to start with.

What is it not doing that you want it to do?

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 16, 2022, 6:10pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/5 "2022-06-16T18:10:09Z")

</div>

The creation of new a post seems to work but in `create_project_old` I have the line of `profile = request.user.profile` and ` project.owner = profile`. In `create_project_new` they do not appear so I was wondering if I have to add them?

---

<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:** [June 16, 2022, 6:39pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/6 "2022-06-16T18:39:49Z")

</div>

If you want to assign the `owner` attribute of the `project` object to `request.user.profile`, then yes.

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 17, 2022, 5:31pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/7 "2022-06-17T17:31:11Z")

</div>

So I want that a project is always related to a specific owner. Would the following code be right then

```auto
def create_project_new(request):
    profile = request.user.profile
    form = ProjectForm()
    form2 = ProjectImageForm()

    if request.method == 'POST':
        form = ProjectForm(request.POST)
        form2 = ProjectImageForm(request.POST, request.FILES)
        images = request.FILES.getlist('image')
        if form.is_valid() and form2.is_valid():
            project.owner = profile
            title = form.cleaned_data['title']
            describ = form.cleaned_data['describtion']
            price = form.cleaned_data['price']
            project_instance = Project.objects.create(
                title=title, describtion=describ, price=price)
            print(project_instance)

            for i in images:
                ProjectImage.objects.create(project=project_instance, image=i)
            return redirect('projects')

    context = {'form': form, 'form2': form2}
    return render(request, 'projects/project_form.html', context)

```

---

<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:** [June 17, 2022, 6:57pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/8 "2022-06-17T18:57:17Z")

</div>

Since ProjectForm is a ModelForm for Project, it’s a lot easier than that.

You have from your `create_project_old`:

> [@PhilEXverse](#):
>
> ```auto
> if request.method == 'POST':
> form = ProjectForm(request.POST, request.FILES)
> if form.is_valid():
> ##############################
> project = form.save(commit=False)
> project.owner = profile
> project.save()
> ##############################
> 
> ```

The part marked out in “#” doesn’t need to be changed just because you’re adding a second form on your page. You don’t need to manually build the Project object.

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 17, 2022, 9:24pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/9 "2022-06-17T21:24:08Z")

</div>

Sorry but I do not really get the content here. My new view for creating a project is `create_project_new`. But you send me the old view `create_project_old`. My question was if I have to add the lines `profile = request.user.profile` and `project.owner = profile` which I have in my old view but not in my new view. Nevertheless `create_project_new` seems to work. Thanks.

---

<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:** [June 17, 2022, 9:36pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/10 "2022-06-17T21:36:20Z")

</div>

I pointed out that what you have in `create_project_old` is what you should be doing in `create_project_new`, _not_ all that extra code that you added to `create_project_new` for creating the Project object.

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 18, 2022, 6:24am UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/11 "2022-06-18T06:24:46Z")

</div>

So in my views I am defining just one form? And in addition this part:

````nohighlight
                ProjectImage.objects.create(project=project_instance, image=i)
            return redirect('projects')```
isn´t necassary?
````

---

<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:** [June 18, 2022, 10:39am UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/12 "2022-06-18T10:39:14Z")

</div>

Within your new view, you have:

> [@PhilEXverse](#):
>
> ```auto
> if form.is_valid() and form2.is_valid():
> project.owner = profile
> title = form.cleaned_data['title']
> describ = form.cleaned_data['describtion']
> price = form.cleaned_data['price']
> project_instance = Project.objects.create(
> title=title, describtion=describ, price=price)
> print(project_instance)
> 
> ```

This specific block of code in new:

> [@PhilEXverse](#):
>
> ```auto
> project.owner = profile
> title = form.cleaned_data['title']
> describ = form.cleaned_data['describtion']
> price = form.cleaned_data['price']
> project_instance = Project.objects.create(
> title=title, describtion=describ, price=price)
> 
> ```

is manually doing what this block does in the old:

> [@PhilEXverse](#):
>
> ```auto
> project = form.save(commit=False)
> project.owner = profile
> project.save()
> 
> ```

I am _only_ referring to how you’re handling the `Project` object - none of what I’m addressing here is any reference to how you’re handling ProjectImage.  
(That’s a follow-on topic that I’ll address after we’re clear here - I’m trying to avoid confusion between the two.)

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 18, 2022, 8:39pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/13 "2022-06-18T20:39:09Z")

</div>

Okay now I am getting it. Thanks. So what you have posted is all for`ProjectForm` in the `create_project_new` right? Like this:

```auto
def create_project_new(request):
    form = ProjectForm()
    profile = request.user.profile

        if form.is_valid():
            project.owner = profile
            title = form.cleaned_data['title']
            describ = form.cleaned_data['describtion']
            price = form.cleaned_data['price']
            project_instance = Project.objects.create(
                title=title, describtion=describ, price=price)
            print(project_instance)

    context = {'form': form}
    return render(request, 'projects/project_form.html', context)

```

---

<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:** [June 18, 2022, 11:18pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/14 "2022-06-18T23:18:38Z")

</div>

I think there’s still some miscommunication here.

What you have here:

> [@PhilEXverse](#):
>
> ```auto
> project.owner = profile
> title = form.cleaned_data['title']
> describ = form.cleaned_data['describtion']
> price = form.cleaned_data['price']
> project_instance = Project.objects.create(
> title=title, describtion=describ, price=price)
> 
> ```

This is what you **don’t** want to have to create your Project model.

What you had originally in your “old” version is what you want to use.

> [@PhilEXverse](#):
>
> ```auto
> project = form.save(commit=False)
> project.owner = profile
> project.save()
> 
> ```

**This** code replaces what you are showing for your “new” method.

And again for clarity, this is only addressing the part of this method for creating the `Project` object. You still need the appropriate code to create the `ProjectImage` instances in the same view.

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 19, 2022, 9:47am UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/15 "2022-06-19T09:47:13Z")

</div>

Ok I think that should do it for the `Project` object. I have defined the `ProjectImage` object as well but I did not do anything after validating it for now.

```auto
def create_project_new(request):
    form = ProjectForm()
    form2 = ProjectImageForm()
    profile = request.user.profile

    if request.method == 'POST':
        form = ProjectForm(request.POST)
        form2 = ProjectImageForm(request.POST, request.FILES)
        images = request.FILES.getlist('image')

        if form.is_valid() and form2.is_valid():
            project = form.save(commit=False)
            project.owner = profile
            project.save()
    context = {'form':form, 'form2':form2}
    return render(request, 'projects/project_form.html', context)

```

---

<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:** [June 19, 2022, 1:30pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/16 "2022-06-19T13:30:28Z")

</div>

Good. Now for the ProjectImage objects, you’ve defined a ModelForm for them. However, you’re not actually using that form as a ModelForm.

I actually wouldn’t make a separate form for this - and certainly not a ModelForm.

I’d add a project\_image field to the Project form. Not as a model field, but as an additional form field.

That reduces the need from two forms to one, generally simplifying the code.

You can still create your ProjectImage objects the same way you have shown in your method.

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 19, 2022, 3:06pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/17 "2022-06-19T15:06:01Z")

</div>

Do you mean something like that? In addition I keep two models right?  
forms.py:

```auto
class ProjectForm(ModelForm):
    image = forms.ImageField(widget=ClearableFileInput(attrs={'multiple':True}))
    class Meta:
        model = Project
        fields = ['title', 'describtion', 'price']

```

models.py

```auto
class Project(models.Model):
    owner = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    describtion = models.TextField(null=True, blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2, default=10)
    id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)

    def __str__ (self):
        return self.title

class ProjectImage(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    image = models.FileField(upload_to="products/")
    
    def __str__ (self):
        return self.image

```

---

<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:** [June 19, 2022, 3:24pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/18 "2022-06-19T15:24:19Z")

</div>

This is correct - in both cases. (Form and Models)

---

<div class="post-metadata">

**Author:** ![PhilEXverse](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/philexverse/32/7373_2.png) [@PhilEXverse](https://forum.djangoproject.com/u/PhilEXverse)\
**Post date:** [June 19, 2022, 3:51pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/19 "2022-06-19T15:51:08Z")

</div>

**You can still create your ProjectImage objects the same way you have shown in your method.**  
Do you mean my first `create_project_new` or `create_project_old`?

So then my view should look like this:

```auto
def create_project_new(request):
    form = ProjectForm()
    profile = request.user.profile

    if request.method == 'POST':
        form = ProjectForm(request.POST)
        images = request.FILES.getlist('image')

        if form.is_valid():
            project = form.save(commit=False)
            project.owner = profile
            project.save()
    context = {'form':form}
    return render(request, 'projects/project_form.html', context)

```

---

<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:** [June 19, 2022, 4:07pm UTC](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323/20 "2022-06-19T16:07:45Z")

</div>

In create\_project\_new. I do not see any code in create\_project\_old that would create any ProjectImage objects. (The only complete instance I see of the old method is in the original post)

[Next page](https://forum.djangoproject.com/t/django-crud-functionality-with-2-models/14323.md?page=2)
