Search code examples
pythondjangodjango-formsmodelform

How to provide requested user in initial values with django ModelForm and assign the form in django admin


I'd like to create articles with ModelForm and generic CreateView without choosing my user as author. Author should be the requested user. I know it can be solved in multiple ways, but I'd like to solve it with a form that I can use everywhere (django-admin and views).

So far, I've tried this:

models.py

class Article(TimeStampedModel):
    ...
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               on_delete=models.CASCADE)
    content = RichTextUploadingField(config_name='default')
    status = models.CharField(max_length=10,
                              choices=STATUS_CHOICES,
                              default='draft')
    ...

forms.py

class ArticleCreateForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = [
            'title', 'featured_image', 'content', 'status'
        ]
    
    author = forms.IntegerField(widget=forms.HiddenInput)
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        user_field = kwargs.get('instance')
        self.fields['author'].initial = user_field.id

views.py

class ArticleCreate(CreateView):
    form_class = ArticleCreateForm
    template_name = 'articles/article_form.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(instance=request.user)
        return render(request, self.template_name, {'form': form})

    def form_valid(self, form):
        return super().form_valid(form)

    def form_invalid(self, form):
        return HttpResponse(str(form.errors))

It renders the form, but instead of saving the article, it throws this error:

  File "/home/tareq/Desktop/PERSONAL/Blog/blog/blog/articles/forms.py", line 19, in __init__
    self.fields['author'].initial = user_field.id
AttributeError: 'NoneType' object has no attribute 'id'
ERROR 2021-01-23 00:58:31,533 log 85374 140159710901824 Internal Server Error: /new/
Traceback (most recent call last):
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/tareq/.pyenv/versions/3.8.0/lib/python3.8/contextlib.py", line 75, in inner
    return func(*args, **kwds)
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/views/generic/base.py", line 97, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/views/generic/edit.py", line 172, in post
    return super().post(request, *args, **kwargs)
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/views/generic/edit.py", line 140, in post
    form = self.get_form()
  File "/home/tareq/.local/share/virtualenvs/Blog-i5phkViF/lib/python3.8/site-packages/django/views/generic/edit.py", line 33, in get_form
    return form_class(**self.get_form_kwargs())
  File "/home/tareq/Desktop/PERSONAL/Blog/blog/blog/articles/forms.py", line 19, in __init__
    self.fields['author'].initial = user_field.id
AttributeError: 'NoneType' object has no attribute 'id'

Solution

  • It seems like you are missing the logic to actually grab the user ID when they are submitting the form. If you take a look at this documentation, you will see that you need to reference the request object to get the user info and have the view logic assign request.user_id to the new instance.

    https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-editing/#models-and-request-user