Show form in a view based on Django classes

1

I have the impression that it must be something simple, but I can not do it with CBV's. I try to render a view that shows the content of a post, and at the same time, in the same view, show a form so that comments can be added to it. The first thing I have, not the second, show the form where you add the comments. All my views are based on classes.

models.py

class Comment(models.Model):

    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    comment = models.TextField()
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                           on_delete=models.CASCADE)

    def get_absolute_url(self):
        return reverse('project_list')

    def __str__(self):
        return self.comment

The view that is supposed to show the form to add comments is very similar to the view used to add a new topic:

views.py

class ProjectDetailView(DetailView):
    model = models.Project
    template_name = 'portfolio/project_detail.html'
    fields = ['comment']

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

In the template I show the detail of the post and at the same time I try to show the form where to add comments, here I lose myself. If I add them from the admin I see them, but not the form.

p_detail.html

<p>{{ project.description|safe }}</p>


{% for comment in project.comment_set.all %}
<div class="comment">
    {{ comment.body|linebreaks }}
</div>
{% empty %}
<p>There are no comments yet.</p>
{% endfor %}

{% if new_comment %}
  <h2>Your comment has been added.</h2>
{% else %}
<h2>Add a new comment</h2>
<form action="." method="post">
     {% csrf_token %}
    {{ form.as_p }}
    <p><input type="submit" value="Add comment">    </p>
</form>
{% endif %}

and this is the url with which I show the detail of the post

urls.py

urlpatterns = [

  path('<int:pk>/', views.ProjectDetailView.as_view(),
     name='project_detail'),

Thank you in advance.

       Environment:


    Request Method: POST
    Request URL: http://127.0.0.1:8000/23/

    Django Version: 2.0.2
    Python Version: 3.6.5
    Installed Applications:
    ['django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crispy_forms',
    'ckeditor',
    'ckeditor_uploader',
    'core',
    'users',
    'portfolio.apps.PortfolioConfig']
    Installed Middleware:
    ['django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware']



    Traceback:

    File "/home/rni/workspace/pyt/web-personal/env/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
    35.             response = get_response(request)

    File "/home/rni/workspace/pyt/web-personal/env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
    128.                 response = self.process_exception_by_middleware(e, request)

    File "/home/rni/workspace/pyt/web-personal/env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
    126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

    File "/home/rni/workspace/pyt/web-personal/env/lib/python3.6/site-packages/django/views/generic/base.py" in view
    69.             return self.dispatch(request, *args, **kwargs)

    File "/home/rni/workspace/pyt/web-personal/env/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
    89.         return handler(request, *args, **kwargs)

    File "/home/rni/workspace/pyt/web-personal/webpersonal/portfolio/views.py" in post
    36.         context = self.get_context_data(*args, **kwargs)

    File "/home/rni/workspace/pyt/web-personal/webpersonal/portfolio/views.py" in get_context_data
    31.         context = super(ProjectDetailView, self).get_context_data(*args, **kwargs)

    File "/home/rni/workspace/pyt/web-personal/env/lib/python3.6/site-packages/django/views/generic/detail.py" in get_context_data
    93.         if self.object:

    Exception Type: AttributeError at /23/
    Exception Value: 'ProjectDetailView' object has no attribute 'object'
    
asked by Matik 06.07.2018 в 01:27
source

1 answer

0

I think your mistake is in assuming that the class DetailView implements the form_valid or form_invalid methods. If you define the form_valid in your ProjectDetailView simply nothing will happen because there is no caller. Unlike CreateView and UpdateView that implement the ModelFormMixin (and therefore the aforementioned methods), DetailView does not do so since it is a detail view.

You have to do it manually within your CBV:

class ProjectDetailView(DetailView):
    model = models.Project
    template_name = 'portfolio/project_detail.html'
    fields = ['comment']
    form_class = CommentForm # O como lo hayas nombrado

    def get_context_data(self, *args, **kwargs):
        context = super(ProjectDetailView, self).get_context_data(*args, **kwargs)
        context['form'] = self.form_class() 
        return context

    def post(self, request, *args, **kwargs):
        context = self.get_context_data(*args, **kwargs)
        form = self.form_class(self.request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.author = self.request.user
            comment.save()
            return redirect('redirige a algún lado')
        # Si el formulario es inválido, queremos que se muestre en el template
        context['form'] = form
        return self.render_to_response(context)

The other thing that occurs to me is that your ProjectDetailView inherits the mixin ModelFormMixin , but I'm not sure if it works. We should try it.

    
answered by 06.07.2018 в 01:55