How to set ForeignKey in CreateView?

PythonDjangoDjango Class-Based-Views

Python Problem Overview


I have a model:

class Article(models.Model):
    text = models.CharField()
    author = models.ForeignKey(User)

How do I write class-based view that creates a new model instance and sets author foreign key to request.user?

Update:

Solution moved to separate answer below.

Python Solutions


Solution 1 - Python

I solved this by overriding form_valid method. Here is verbose style to clarify things:

class CreateArticle(CreateView):
    model = Article

    def form_valid(self, form):
        article = form.save(commit=False)
        article.author = self.request.user
        #article.save()  # This is redundant, see comments.
        return super(CreateArticle, self).form_valid(form)

Yet we can make it short (thanks dowjones123), this case is mentioned in docs.:

class CreateArticle(CreateView):
    model = Article

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

Solution 2 - Python

I just stumbled into this problem and this thread led me in the right direction (thank you!). Based on this Django documentation page, we can avoid calling the form's save() method at all:

class CreateArticle(LoginRequiredMixin, CreateView):
    model = Article

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

Solution 3 - Python

Berislav's code in views.py doesn't work for me. The form is rendered as expected, with the user value in a hidden input, but the form is not saved (I don't know why). I have tried a slightly different approach, that works for me:

views.py
from django.views.generic import *
from myapp.forms import ArticleForm
from myapp.models import Article

class NewArticleView(CreateView):
    model = Article
    form_class = ArticleForm
    def get_initial(self):
        return {
            "user": self.request.user
        }

Solution 4 - Python

You should set up a CreateView using a ModelForm for that model. In the form definition, you set the ForeignKey to have the HiddenInput widget, and then use the get_form method on the view to set the value of your user:

forms.py:

from django import forms

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        widgets = {"user": forms.HiddenInput()}

views.py:

from django.views.generic import *
from myapp.forms import ArticleForm
from myapp.models import Article

class NewArticleView(CreateView):
    model = Article
    form_class = ArticleForm
    def get_form(self, form_class):
        initials = {
            "user": self.request.user
        }
        form = form_class(initial=initials)
        return form

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVlad T.View Question on Stackoverflow
Solution 1 - PythonVlad T.View Answer on Stackoverflow
Solution 2 - PythonCarlos MermingasView Answer on Stackoverflow
Solution 3 - PythonjantoniomartinView Answer on Stackoverflow
Solution 4 - PythonBerislav LopacView Answer on Stackoverflow