Home > Blockchain >  local variable 'comment_form' referenced before assignment in django
local variable 'comment_form' referenced before assignment in django

Time:01-29

I created an app where user can login and post a contents he wants: and now i decided to add comment section to each post user did in the app, i followed the tutorial in djangocentral website, but it's not working after i added everything they did into my app, when i click on [Read more] it's throw me an error in the browser: local variable 'comment_form' referenced before assignment, if i deleted the: 'comment_form' inside the context of my viewPhoto view its shows nothing in viewPhoto template. How can i do this ?

the model:

class Comment(models.Model):
    post = models.ForeignKey(Photo, on_delete=models.CASCADE, related_name='comments')
    name = models.CharField(max_length=80) 
    email = models.EmailField()
    body = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=False)

    class Meta:
        ordering = ['created_on']

    def __str__(self):
        return 'Comment {} by {}'.format(self.body, self.name)  

the admin.py:

from django.contrib import admin
from .models import Photo, Category, Comment

# Register your models here.
admin.site.register(Category)
admin.site.register(Photo)
@admin.register(Comment)

class CommentAdmin(admin.ModelAdmin):
    list_display = ('name', 'body', 'post', 'created_on', 'active')
    list_filter = ('active', 'created_on')
    search_fields = ('name', 'email', 'body')
    actions = ['approve_cooments']


    def approve_comment(self, request, queryset):
        queryset.update(active=True)

the form.py:

from dataclasses import fields
from pyexpat import model
from .models import Comment
from django import forms


class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ('name', 'email', 'body',)

the view.py:

def viewPhoto(request, pk):
    post = get_object_or_404(Photo, id=pk)
    photo = Photo.objects.get(id=pk)

    template_name = 'photo.html'
    comment = post.comments.filter(active=True)
    new_comment = None


    if request.method == 'POST':
        comment_form = CommentForm(data=request.POST)
        if comment_form.is_valid():

            new_comment = comment_form.save(commit=False)

            new_comment.post = post

            new_comment.save()
        else:
            comment_form = CommentForm()
    return render(request, 'photo.html', {'photo': photo, 'post': post, 
    'comment':comment, 
    'new_comment': new_comment,
    'comment_form': comment_form})

viewPhoto template:

<body >
<div >
     <div >
          <div >
               <div style="height: 90vh;">
                  <img style="max-width: 100%; max-height: 100%" src="{{ post.image.url }}" alt="">

                  <p>{{post.description}}</p>
                  <p>{{post.user.username.upper}}</p>
                  <p>{{post.date_added}}</p>

               </div>

          </div>
     </div>
</div>
 <div >
      {% for comment in comments %}
      <p>{{ comment.name }}</p>
      <br>
      <p>{{ comment.created_on }}</p>
      <br>
      <p>{{ comment.body }}</p>
      {% endfor %}
 </div>


<div >
     {% if new_comments %}
     <p>wait your comments is ready</p>

     <form method="POST"> 
          {% csrf_token %}             
          {{ comment_form.as_p }}
          <button type="submit">submit</button>
     </form>
     {% endif %}
</div>

CodePudding user response:

The else should bind with the if request.method == 'POST' check, not with the if comment_form.is_valid() check, so:

from django.shortcuts import redirect

def viewPhoto(request, pk):
    post = get_object_or_404(Photo, id=pk)
    photo = Photo.objects.get(id=pk)

    template_name = 'photo.html'
    comment = post.comments.filter(active=True)
    new_comment = None


    if request.method == 'POST':
        comment_form = CommentForm(data=request.POST)
        if comment_form.is_valid():
            comment_form.instance.post = post
            comment_form.save()
            return redirect('name-of-some-view')
    else:
        comment_form = CommentForm()
    return render(request, 'photo.html', {'photo': photo, 'post': post, 
    'comment':comment, 
    'new_comment': new_comment,
    'comment_form': comment_form})

Note: In case of a successful POST request, you should make a redirect [Django-doc] to implement the Post/Redirect/Get pattern [wiki]. This avoids that you make the same POST request when the user refreshes the browser.

CodePudding user response:

I think i can help you it's pretty straight forward to render comment in your frontend. You either get the comment by related name or just getting it from the comment model. Django is all about simplicity and writing clean codes My solution:

from django.shortcuts import redirect

def viewPhoto(request,pk):
    # We are getting the comment by related name ('comments')
    post = Photo.objects.prefetch_related('comments').get(pk=pk)
    # Here is where we make the comment logic 
    if request.method == 'POST':
        comment_form = CommentForm(request.POST)
        if comment_form.is_valid():
            new_comment = comment_form.save(commit=False)
            comment_form.instance.post = post
            new_comment.save()
            # here you redirect after form have been saved to another view 
            return redirect('home') # would redirect to your home if have a home url name.
        else:
            comment_form = CommentForm()
    return render(request,'photo.html/',{'post': post,'comment_form':comment_form})

We would have to work on you template to refactor the html rendering of comment and post. It's always good to keep things simple and clean.

body >
<div >
     <div >
          <div >
               <div style="height: 90vh;">
                  <img style="max-width: 100%; max-height: 100%" src="{{ post.image.url }}" alt="">

                  <p>{{post.description}}</p>
                  <p>{{post.user.username}}</p>
                  <p>{{post.date_added}}</p>

               </div>

          </div>
     </div>
</div>
 <div >
      {% for comment in post.comments.all %}
      <p>{{ comment.name }}</p>
      <br>
      <p>{{ comment.created_on }}</p>
      <br>
      <p>{{ comment.body }}</p>
      {% endfor %}
 </div>


<div >
     {% if new_comments %}
     <p>wait your comments is ready</p>

     <form method="POST"> 
         {% csrf_token %}             
         {{ comment_form.as_p }}
       <button type="submit">submit</button>
     </form>
     {% endif %}
</div>
  •  Tags:  
  • Related