0

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'
Tareq Monwer
  • 185
  • 1
  • 13

1 Answers1

0

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

brandonris1
  • 455
  • 3
  • 9
  • I'm not sure, because when I assign request.user in form instance's field, form_invalid get's called showing 'author field is required'. Another thing, I need the django admin to do same, save current user as author instead of showing select options. – Tareq Monwer Jan 22 '21 at 20:29
  • This may be a stupid question, but when you try to test this, are you actually logged in? I noticed that your view logic didn't have LoginRequiredMixin. – brandonris1 Jan 22 '21 at 20:32
  • Also, for having the same logic in the Admin, it looks like this post may solve your problem as well: https://stackoverflow.com/questions/65847783/how-to-attach-current-logged-in-user-to-object-when-object-is-created-from-djang – brandonris1 Jan 22 '21 at 20:38
  • Yes, I'm logged in, didn't use the mixin :P – Tareq Monwer Jan 22 '21 at 20:41
  • So I think you are getting the author field is required error because you have added it as a form field even though its not included in the list of fields. I'm betting that if you remove that line in your form, then update the view to set the author of the instance equal to request.user.id then you should be good to go. – brandonris1 Jan 22 '21 at 21:00
  • I got that working. But admin dropdown thing is still hung up. That solution above shows `user has no attribute widget` in the admin. – Tareq Monwer Jan 22 '21 at 21:36
  • Actually, this answer is right. My application has import-export package in admin. Maybe that is causing the issue. I tested these codes in a new codebase, and everything worked as expected. Thanks @brandonris1 – Tareq Monwer Jan 22 '21 at 21:43