How can I automatically add user's info to a model in Django?

I have a status and user apps in my project and all the statuses are obviously created by particular users. I want to keep info about statuses creators (id) in my db, but I don't know how to add it automatically - without having a field in a form. Like I'm just authenticated, I create a status and my db knows it was me. I tried to do this with an initial parameter but it didn't work out. Files that I attached are from the status app

views.py

...
class StatusCreateView(View):
    def get(self, request, *args, **kwargs):
        form = StatusForm()
        return render(request, "statuses/create.html", {"form": form})

    def post(self, request, *args, **kwargs):
        form = StatusForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("statuses_list")
        return render(request, "statuses/create.html", {"form": form})
...

urls.py

...
urlpatterns = [
    path("", views.IndexView.as_view(), name="statuses_list"),
    path("create/", views.StatusCreateView.as_view(), name="statuses_create"),
...
]

models.py

from django.db import models


# Create your models here.
class Status(models.Model):
    name = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    author = models.ForeignKey(
        "user.CustomUser",
        on_delete=models.CASCADE,
        related_name='status_related_author'
    )

forms.py

from django.forms import ModelForm
from .models import Status


class StatusForm(ModelForm):
    class Meta:
        model = Status
        fields = ["name"]

templates/statuses/create.html

{% if form.errors %}
<div>
    <ul>
    {% for error in form.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ul>
</div>
{% endif %}
<form action="{% url 'statuses_create' %}" method="post">
    {% csrf_token %}
    <table border="1">
    {{ form }}
    </table>
    <input type="submit" value="Создать">
</form>

First I would advise to make the author non-editable then:

class Status(models.Model):
    name = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    author = models.ForeignKey(
        'user.CustomUser',
        editable=False,
        on_delete=models.CASCADE,
        related_name='status_related_author',
    )

although not necessary, it makes your life easier, because it will not show up in ModelForms now, even if fields = __all__.

Next in the view, you can inject the author to the .instance of the form, so:

class StatusCreateView(View):
    def get(self, request, *args, **kwargs):
        form = StatusForm()
        return render(request, 'statuses/create.html', {'form': form})

    def post(self, request, *args, **kwargs):
        form = StatusForm(request.POST)
        if form.is_valid():
            form.instance.author = self.request.user
            form.save()
            return redirect('statuses_list')
        return render(request, 'statuses/create.html', {'form': form})

This will of course require that the person is authenticated, and we can scrap a lot of boilerplate with a CreateView:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView


class AuthorCreateView(LoginRequiredMixin, CreateView):
    model = Status
    fields = ['name']
    template_name = 'statuses/create.html'
    success_url = reverse_lazy('statuses_list')

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Back to Top