# Django set formset with current user

**URL:** https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737
**Category:** Using Django
**Created:** [September 17, 2021, 11:15pm UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737 "2021-09-17T23:15:18Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![shawnngtq](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/shawnngtq/32/5834_2.png) [@shawnngtq](https://forum.djangoproject.com/u/shawnngtq)
#### Post date: [September 17, 2021, 11:15pm UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/1 "2021-09-17T23:15:19Z")

</div>

## Version

Django 3.2.7

## Context

I have a form that contains multiple inlineformset\_factory formset.

For all my models, they all have a meta field call `created_by` .

Main form is using a model call `Person`, with many formsets, for example, `PersonEmailFormSet` and `PersonImageFormSet`

## Problem

Only the main form Person’s `created_by` is filled by current user. For all the formsets (emailfs, imagefs), how can I set their `created_by` with current user?

## Code

Here is my views and my 7 different failed approaches.

```python
# home models.py
# base abstract model that all my models inherit
from urllib.parse import urlparse

from django.contrib.auth.models import User
from django.db import models

class Base(models.Model):
    created_at = models.DateTimeField(
        auto_now_add=True,
    )
    updated_at = models.DateTimeField(
        auto_now=True,
    )
    created_by = models.ForeignKey(
        User,
        editable=False,
        null=True,
        on_delete=models.SET_NULL,
        related_name="%(class)s_created_by",
    )
    updated_by = models.ForeignKey(
        User,
        editable=False,
        null=True,
        on_delete=models.SET_NULL,
        related_name="%(class)s_updated_by",
    )

    class Meta:
        abstract = True
        ordering = ["-pk"]

```

```python
# personimage models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from imagekit.models import ProcessedImageField

from home.models import Base
from person.models import Person

# Create your models here.
class PersonImage(Base):
    person = models.ForeignKey(
        Person,
        null=True,
        on_delete=models.SET_NULL,
        related_name="person_image",
    )
    image = ProcessedImageField(
        format="WEBP",
        upload_to=update_person_image_name,
    )

    class Meta:
        db_table = "person_image"

    def __str__ (self):
        return str(self.image)

```

```python
# personimage forms.py
from django import forms
from django.utils.translation import gettext_lazy as _

from home.forms import MetadataFormWidget
from person.models import Person
from useruploadfile.models import PersonImage

class PersonImageForm(forms.ModelForm):
    class Meta(MetadataFormWidget):
        model = PersonImage
        exclude = ("version_number",)
        widgets = MetadataFormWidget.widgets.copy()
        person_image_widgets = {
            "image": forms.ClearableFileInput(
                attrs={"multiple": False},
            ),
        }
        widgets |= person_image_widgets

    def __init__ (self, *args, **kwargs):
        # For method 6, 7 attempts
        # self.created_by = created_by
        super(). __init__ (*args, **kwargs)

PersonImageFormSet = forms.models.inlineformset_factory(
    Person,
    PersonImage,
    form=PersonImageForm,
    can_delete=False,
    error_messages={
        "image": {
            "required": _(
                "Please provide image for us to ensure that this person is unique"
            )
        }
    },
    extra=0,
    min_num=1,
    validate_min=True,
)

```

```python
# Person views.py
class PersonCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    ...
    model = Person
    form_class = PersonForm

    def get_context_data(self, **kwargs):
        context = super(PersonCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            context["emailfs"] = PersonEmailFormSet(
                self.request.POST, self.request.FILES
            )
            context["imagefs"] = PersonImageFormSet(
                self.request.POST, self.request.FILES
            )
            # Method 6
            # context["imagefs"] = PersonImageFormSet(
            # self.request.POST, self.request.FILES, user=self.request.user
            # )
            # Method 7
            # context["imagefs"] = PersonImageFormSet(
            # self.request.POST, self.request.FILES, form_kwargs={'created_by': self.request.user}
            # )
        else:
            context["emailfs"] = PersonEmailFormSet()
            context["imagefs"] = PersonImageFormSet()
        return context

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        context = self.get_context_data()
        emailfs = context["emailfs"]
        imagefs = context["imagefs"]
        personfs = [emailfs, imagefs]
        if (
            form.is_valid()
            and all(fs.is_valid() for fs in personfs)
        ):
            self.object = form.save()
            for fs in personfs:
                # Method 1
                # fs.created_by = self.request.user
                # Method 2
                # self.created_by = self.request.user
                fs.instance = self.object
                # Method 3
                # fs.created_by = self.request.user
                # Method 4
                # fs.instance.created_by = self.request.user
                # Method 5
                # for f in fs.forms:
                # f.user = self.request.user
                # f.save()
                fs.save()
        else:
            return self.form_invalid(form)
        return super(PersonCreateView, self).form_valid(form)

```

---

<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: [September 17, 2021, 11:31pm UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/2 "2021-09-17T23:31:05Z")

</div>

We’ll need to see more - at least the Models behind “PersonEmailFormSet” (or ImageFormSet) and the formset definitions.

In general, you need to iterate through the individual forms. See [Overriding clean on a model formset.](https://docs.djangoproject.com/en/3.2/topics/forms/modelforms/#overriding-clean-on-a-modelformset)

---

<div class="post-metadata">

### Author: ![shawnngtq](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/shawnngtq/32/5834_2.png) [@shawnngtq](https://forum.djangoproject.com/u/shawnngtq)
#### Post date: [September 18, 2021, 12:10am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/3 "2021-09-18T00:10:40Z")

</div>

I just updated with the PersonImage model + formset definitions.

I don’t use the Formset `clean` method since they are used as inlineformset\_factory, not sure if it works / recommended.

The only place that contains the save logic is under Person `views.py` CreateView.

---

<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: [September 18, 2021, 12:14am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/4 "2021-09-18T00:14:51Z")

</div>

Ok, I don’t see a created\_by field in the PersonImage model. Nothing you do in the form for it is going to be saved.

A formset is just a collection of forms. Each form within a formset is a form, is handled and managed like any other form.

---

<div class="post-metadata">

### Author: ![shawnngtq](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/shawnngtq/32/5834_2.png) [@shawnngtq](https://forum.djangoproject.com/u/shawnngtq)
#### Post date: [September 18, 2021, 12:17am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/5 "2021-09-18T00:17:56Z")

</div>

The `PersonImage` inherit the `Base` abstract model. All my models inherit `Base` abstract models.

So it has `created_at`, `updated_at`, `created_by_id` and `updated_by_id` columns in database. When I try to add, I am using `created_by`

---

<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: [September 18, 2021, 12:19am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/6 "2021-09-18T00:19:15Z")

</div>

Got it.

Ok, when your formsets are submitted, you need to follow the pattern as described in the docs I linked in my previous response.

---

<div class="post-metadata">

### Author: ![shawnngtq](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/shawnngtq/32/5834_2.png) [@shawnngtq](https://forum.djangoproject.com/u/shawnngtq)
#### Post date: [September 18, 2021, 12:33am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/7 "2021-09-18T00:33:43Z")

</div>

Not sure where I screw up, after I update the PersonImage ModelForm by adding the `clean` method like the doc, it would throw error `AttributeError: 'PersonImageForm' object has no attribute 'forms'`

```python
class PersonImageForm(forms.ModelForm):

    class Meta(MetadataFormWidget):
        model = PersonImage
        exclude = ("version_number",)
        widgets = MetadataFormWidget.widgets.copy()
        person_image_widgets = {
            "image": forms.ClearableFileInput(
                attrs={"multiple": False},
            ),
        }
        widgets |= person_image_widgets

    def __init__ (self, *args, **kwargs):
        super(). __init__ (*args, **kwargs)
    
    # This portion return this error
    # AttributeError: 'PersonImageForm' object has no attribute 'forms'
    def clean(self):
        super().clean()
        for form in self.forms:
            form.instance.created_by = self.request.user

```

---

<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: [September 18, 2021, 12:36am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/8 "2021-09-18T00:36:01Z")

</div>

That’s because PersonImageForm is a form. it’s not a set of forms. The formset is the set of forms.

---

<div class="post-metadata">

### Author: ![shawnngtq](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/shawnngtq/32/5834_2.png) [@shawnngtq](https://forum.djangoproject.com/u/shawnngtq)
#### Post date: [September 18, 2021, 12:49am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/9 "2021-09-18T00:49:16Z")

</div>

Alright, so it means I need to change my `PersonImageFormSet` from `inlineformset_factory` to `BaseInlineFormSet` in order to define the `clean` method?

```python
PersonImageFormSet = forms.models.inlineformset_factory(
    Person,
    PersonImage,
    form=PersonImageForm,
    can_delete=False,
    error_messages={
        "image": {
            "required": _(
                "Please provide image for us to ensure that this person is unique"
            )
        }
    },
    extra=0,
    min_num=1,
    validate_min=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: [September 18, 2021, 1:46am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/10 "2021-09-18T01:46:38Z")

</div>

Not quite - as documented in the examples at [Overriding methods on an `InlineFormSet`](https://docs.djangoproject.com/en/3.2/topics/forms/modelforms/#overriding-methods-on-an-inlineformset), you define a custom formset class that inherits from BaseInlineFormSet, then pass it as the formset parameter in your call to inlineformset\_factory.

---

<div class="post-metadata">

### Author: ![shawnngtq](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/shawnngtq/32/5834_2.png) [@shawnngtq](https://forum.djangoproject.com/u/shawnngtq)
#### Post date: [September 18, 2021, 7:09am UTC](https://forum.djangoproject.com/t/django-set-formset-with-current-user/9737/11 "2021-09-18T07:09:17Z")

</div>

Thanks for pointing me to the right direction. Finally understand that you can have both `form` and `formset` under `inlineformset_factory`.
