Voting

We need to allow users to vote on submissions. To keep things simple, we'll only allow upvotes. A user can indicate that they like a submission. There is no way to indicate disapproval. This keeps the code and UI simple. We also want to ensure that one user can upvote a submission only once and they can remove their upvotes if they change their minds or upvoted a submission by mistake.

If you take another look at the Link model, you'll see we already have an upvotes field, which is a Machine to machine (M2M) with the User model. This is the only database entry we'll need to allow and keep track of upvotes by users. In order to upvote a submission, users will click on a link next to the submission. Until now, we were able to make do without a page to list all submissions. It's a good idea to create one now so that we can access and upvote the various submissions. We can't keep creating new submissions every time we want to test something.

First, create this view in links/views.py. Remember to import TemplateView from django.views.generic first:

class HomeView(TemplateView):
    template_name = 'home.html'

    def get_context_data(self, **kwargs):
        ctx = super(HomeView, self).get_context_data(**kwargs)
        ctx['submissions'] = Link.objects.all()

        return ctx

Next, change the template at template/home.html to the following:

{% extends "base.html" %}

{% block content %}
    <h1>Welcome to Discuss</h1>
    <h2>Submissions</h2>
    <ul>
        {% for submission in submissions %}
        <li>
            <a href="{{ submission.url }}" target="_blank">{{ submission.title }}</a>
            <i><a href="{% url "submission-detail" pk=submission.pk %}">Comments</a></i>
        </li>
        {% endfor %}
    </ul>
{% endblock %}

Import our new HomeView at the top of discuss/urls.py and note the home URL configuration in discuss/urls.py:

url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),

Change the preceding code to this:

url(r'^$', HomeView.as_view(), name='home'),

Finally, let's provide our users with a handy link to the home page in the navigation bar. In the base.html template (in the templates directory in the project root), add this as the first list element of the navigation list outside of the user authentication if condition:

<li><a href="{% url "home" %}">Home</a></li>

That's it. There's nothing new in this code. It's pretty easy to understand and you should have a clear idea of what's happening here by now. Let's look at the end result. If you now open the home page of our app by browsing to http://127.0.0.1:8000 in your browser, you should see something similar to the following screenshot. Of course, your page will not be the same as this as you will have added your own test content:

Voting

You'll see a list of submissions. If you click on any, you'll have a new tab open with the link for that submission. You'll also see a Comments link next to each submission. Clicking on this takes you to the submission detail page.

Let's talk a bit about how we're going to implement the upvoting feature. The M2M upvotes field that we created in the Link model should give you a hint. Whenever a user upvotes a submission, we add them to this relationship. As an M2M relationship ensures that if we add the same object multiple times it doesn't create a new record, we easily ensure that one user can vote on a submission only once.

Let's create a view that adds the logged in user to the upvoters list of a submission and then takes them back to the home page. We'll also add a link to each submission on the home page that lets the user upvote the submission with this new view.

In links/views.py, import the View generic view class from django.views.generic, and then create this view:

class UpvoteSubmissionView(View):
    def get(self, request, link_pk, **kwargs):
        link = Link.objects.get(pk=link_pk)
        link.upvotes.add(request.user)

        return HttpResponseRedirect(reverse('home'))

Next, import this new view in discuss/urls.py and add it to the URL patterns :

url(r'^upvote/(?P<link_pk>d+)/$', UpvoteSubmissionView.as_view(), name='upvote-submission'),

In templates/home.html, add the Upvote link above the submission title link:

<a href="{% url "upvote-submission" link_pk=submission.pk %}">Upvote</a>

Open up the home page and you'll see an Upvote link next to each submission title. Clicking on the link should bring you back to the home page. It should look similar to the following screenshot:

Voting

If you upvote a link, it immediately brings you back to the home page without any indication that your upvote was recorded. The fix for this is simple. Change the Upvote link HTML line that you just added to the home page template to the following:

{% if request.user in submission.upvotes.all %}
  Upvoted
{% else %}
  <a href="{% url "upvote-submission" link_pk=submission.pk %}">Upvote</a>
{% endif %}

If you open up the home page again, you'll see a simple Upvoted text next to submissions that you've already upvoted instead of the link that you saw before. We should also allow the user to remove his upvote from a submission. First, create a new view for this in links/views.py:

class RemoveUpvoteFromSubmissionView(View):
    def get(self, request, link_pk, **kwargs):
        link = Link.objects.get(pk=link_pk)
        link.upvotes.remove(request.user)

        return HttpResponseRedirect(reverse('home'))

This is almost the same as the view we created to record a new upvote. The only difference is that here we use the remove method of the related manager. Next, we'll need to add this to the URLs file at discuss/urls.py. Import our new view here and add the following URL configuration:

url(r'^upvote/(?P<link_pk>d+)/remove/$', RemoveUpvoteFromSubmissionView.as_view(), name='remove-upvote'),

Finally, let's change the Upvoted label that we added to the home page before to be a link to remove the upvote. In your templates/home.html file, note these lines:

{% if request.user in submission.upvotes.all %}
  Upvoted
{% else %}

Change them to the following:

{% if request.user in submission.upvotes.all %}
  <a href="{% url "remove-upvote" link_pk=submission.pk %}">Remove Upvote</a>
      {% else %}

That's it! Now when you visit the home page, you'll see the Remove Upvote link for all the submissions that you have already upvoted. By clicking on the link, you'll be redirected back to the home page with your upvote removed. You should see the Upvote link for that submission again as you can upvote it again.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.232.239