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.
# 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"]
# 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)
# 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,
)
# 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)