0

I have a post detail view as below.

class PostDetailView(AjaxResponseMixin, UpdateView):
model = UserPost
context_object_name = 'post'
template_name = 'feed/post_detail.html'
form_class = CommentForm

def get_initial(self):
    initial_data = super(PostDetailView, self).get_initial()
    obj = self.get_object()
    initial_data.update({
        "content_type": obj.get_content_type,
        "object_id": obj.id
    })
    return initial_data

def get_context_data(self, **kwargs):
    # comment_form = CommentForm
    context = super(PostDetailView, self).get_context_data(**kwargs)
    kwargs['form_comment'] = context['form']  # comment_form
    try:
        total_views = r.incr('userpost:{}:views'.format(self.object.pk))
        kwargs['total_views'] = total_views
    except (redis.exceptions.ConnectionError,
            redis.exceptions.BusyLoadingError):
        pass

    return super(PostDetailView, self).get_context_data(**kwargs)

def get_success_url(self):
    try:
        total_views = r.incr('userpost:{}:views'.format(self.object.pk))
    except (redis.exceptions.ConnectionError,
            redis.exceptions.BusyLoadingError):
        pass
    return reverse_lazy('feed:post_detail', kwargs={'pk': self.object.pk})

def form_valid(self, form):
    c_type = form.cleaned_data.get("content_type")
    obj_id = form.cleaned_data.get('object_id')
    content_data = form.cleaned_data.get("content")
    parent_obj = None
    try:
        parent_id = int(self.request.POST.get("parent_id"))
    except:
        parent_id = None

    if parent_id:
        parent_qs = Comment.objects.filter(pk=parent_id)
        if parent_qs.exists() and parent_qs.count() == 1:
            parent_obj = parent_qs.first()

    new_comment, created = Comment.objects.get_or_create(
        user=self.request.user,
        content_type=c_type,
        object_id=obj_id,
        content=content_data,
        parent=parent_obj,
    )
    if created:
        ct = ContentType.objects.get_for_id(c_type.id)
        obj = ct.get_object_for_this_type(pk=obj_id)
        create_action(self.request.user, 'commented on', obj)
    return super(PostDetailView, self).form_valid(form)

def form_invalid(self, form):
    print("invalid form")

I am writing test case as below.

class PostDetailViewTests(TestCase):
@classmethod
def setUpTestData(cls):
    user = User.objects.create_user(username='chitra', password='password123')
    cls.post = UserPost(author=user, post_body="Test post", )
    cls.post.save()


def setUp(self):
    login = self.client.login(username='chitra', password='password123')
    user = auth.get_user(self.client)
    assert user.is_authenticated

def test_postdetail_view_page_status_code(self):
    """
    Test that a PostDetailView page is rendering correctly
    """
    response = self.client.get(reverse_lazy('feed:post_detail', kwargs={'pk': self.post.pk}))
    self.assertEquals(response.status_code, 200, 'post doesnt exist with pk={}'.format(self.post.pk))
    self.assertTemplateUsed(response, 'feed/post_detail.html', 'Template used is wrong')

def test_postdetail_view_post_comment(self):
    """
    Test that a comment is posted ot post correctly
    """
    user = User.objects.get(pk=1)
    resp = self.client.post(reverse_lazy('feed:post_detail', kwargs={'pk': self.post.pk}), {'content': 'just a comment'})
    self.assertEqual(resp.status_code, 200)
    # co.refresh_from_db()
    self.assertTrue(Comment.objects.filter().exists())

Comment/forms.py

class CommentForm(ModelForm):

class Meta:
    model = Comment
    fields = ['content_type', 'object_id', 'content']  # list of fields you want from model
    widgets = {'content_type':  HiddenInput(), 'object_id': HiddenInput(),
        'content': Textarea(attrs={'rows': 4, 'cols': 65}),
   }

comment/models.py

class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=1)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.CASCADE)
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
objects = CommentManager()

Ok, Here, 'test_postdetail_view_page_status_code' test is passing but posting is getting failed i.e 'test_postdetail_view_post_comment', The resp is None here!

Basically, the view is just a display of a post, and a comment form along with comment list(If there are any), The comment body(i.e field content) is the only input parameter, and content types are used to save the comment object as shown. I am using method 'get_initial', to initialise the content type object with post id(please see), I think the resp is None because I need to first call the display as self.client.get and then use self.client.post here?, I think the get_initial is not getting called, so it's not having content type data right? I am not sure how to debug this to check where the test case is failing!

Any light on this is highly appreciated, Thank you!

Timer
  • 37
  • 1
  • 7
  • Your form_invalid method doesn't return anything. You need to return the result of calling super(). – Daniel Roseman Jul 06 '18 at 17:23
  • @DanielRoseman , Yeah, I will add that later I thought! If I add that, I might get more detail? Anyway, I think, here content type data is not getting initialised which is causing form_invalid I guess, can you tell me how to do that? – Timer Jul 06 '18 at 17:28
  • I mean to say, How should I make post method here to pass? it's working fine from manual testing. – Timer Jul 06 '18 at 17:37
  • This is the wrong approach. You should exclude the content_type and object_id fields from the form fields altogether, and set them in form_valid from the object. – Daniel Roseman Jul 06 '18 at 17:40
  • @DanielRoseman, Thank you Daniel, I managed to make it work like how you said, but do you mind letting me know why my first approach is wrong? – Timer Jul 06 '18 at 17:59
  • Because the form would never be valid if it's expecting the content_type and object_id fields but you're not sending them from the browser. – Daniel Roseman Jul 06 '18 at 19:46
  • @DanielRoseman They're not sent from the browser, but when the page is rendering, we are initialising both of the fields(Through get_initial method), which are hidden in the form, so they will always be there in the form right? – Timer Jul 07 '18 at 04:30
  • How are you outputting them in the template? – Daniel Roseman Jul 07 '18 at 08:22
  • {% csrf_token %} {{ post.post_body }} {% if post.image %} {% endif %} – Timer Jul 07 '18 at 09:30
  • @DanielRoseman just normally like how we access in templates, If you can see above code of comment_form, I am hiding those fields and they're not displaying in template, I am just accessing the initial values I've set in the initial_form in form_valid method and saving! It's working via browser. – Timer Jul 07 '18 at 09:31

0 Answers0