Skip to content
This repository has been archived by the owner on May 28, 2020. It is now read-only.

Setup Showing to only show candidates who are running for a selected office in a selected election #27

Closed
mitchdowney opened this issue Aug 17, 2013 · 9 comments
Milestone

Comments

@mitchdowney
Copy link
Member

Please scroll to the last comments to understand this issue.

image

@scvnc
Copy link
Member

scvnc commented Aug 17, 2013

A route should be set up that provides this modified election view:

/election/:e_id/:o_id

where :e_id is the election id and :o_id is the office id.

Down the road we can support prettier urls

@mitchdowney
Copy link
Member Author

I'd like to learn more about how this would be done.

The current urls.py for showing the election page is:

# SHOW ELECTION - RANDOM CANDIDATES
    url(r'^elections/(?P<pk>\d+)/$', ElectionDetailView.as_view(
        model=Election,
        template_name='election_detail.html',
        context_object_name='election'),
        name='election_detail',
        ),

And the views is just (minus your blocked_users function):

class ElectionDetailView(DetailView):
    model = Election
    context_object_name = "election"

I don't know how to type the urls.py so that it accepts a pk for the election, and a different pk for the office. Maybe something with changing slug_field?

@arocks
Copy link

arocks commented Sep 3, 2013

There are many ways to achieve this. The cleanest way to do this is to implement the query logic in models and override the get_queryset within the DetailView.

Within models.py add a method to Election class to accept a candidate id and office id and return the filtered query set. Just filtering the candidate_set based on office should work. You can debug this in your shell or writes tests to ensure it works.

Next, add a new DetailView in views.py (possibly mapped with the url regex url(r'^elections/(?P<pk>\d+)/office/(?P<office>\d+)/$',) and override the get_queryset as mentioned in the docs.

@mitchdowney
Copy link
Member Author

Thank you arocks!

Well I tried for a few hours with your suggestion, and I can see you have shown the right answer, but I don't understand yet how to use get_queryset. The example in the docs is a ListView (I am using DetailView for the election page that lists its candidates on the page), and is not being passed a def from models.py. I might be too much of a noob to understand this right now.

I'm going to read the docs more closely over the next 2 days so I better understand get_queryset. Thanks again for pointing me in the right direction

@mitchdowney
Copy link
Member Author

Notice that Office and Election each have a ForeignKey relationship with Constituency. This is because an Office is a position within a Constituency, but an Office is not within an Election.

Also, I insert candidates on an ElectionDetailView page by running a for loop on election.candidate_set.all. What I need to resolve this issue is basically run election.candidate_set, but filter it to return only candidates that are running for a specific office (for example, only show all President candidates who are running in this specific election).

urls.py

url(r'^elections/(?P<pk>\d+)/office/(?P<office_id>\d+)/$', ElectionOfficeDetailView.as_view(
    model=Election,
    template_name='election_detail_by_office.html'),
    name='election_detail_by_office',
    ),

models.py

class Constituency(models.Model):
    name = models.CharField(max_length=100)

class Office(models.Model):
    constituency = models.ForeignKey(Constituency)
    name = models.CharField(max_length=30)

class Election(models.Model):
    constituency = models.ForeignKey(Constituency)
    name = models.CharField(max_length=50)
    offices = models.ManyToManyField(Office, blank=True, null=True)

    def get_office_candidates(self, office_id):
        office_candidates = self.candidate_set.filter(office_id=office_id)

        return office_candidates

class Candidate(models.Model):
    user = models.ForeignKey(UserProfile)
    election = models.ForeignKey(Election)
    office = models.ForeignKey(Office)

views.py

class ElectionOfficeDetailView(DetailView):
    model = Election
    context_object_name = "election"

    def get_queryset(self):
        ???
        ???

Is the office_candidates function in models.py correct?

My biggest problem is I am confused about how I should override get_queryset to use get_office_candidates() in the views.py, I am not sure how to apply the example given in the docs to solve this problem:

example def get_queryset from docs

class PublisherBookList(ListView):

    template_name = 'books/books_by_publisher.html'

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name=self.args[0])
        return Book.objects.filter(publisher=self.publisher)

I am sorry for my ignorance. This is the last and biggest issue to resolve for this app to be ready for user testing. Do you have any suggestions for how to solve this?

@suriya
Copy link

suriya commented Sep 6, 2013

get_queryset is useful only if you want DetailView to limit its choices of Election objects.

What you want to do is add a queryset of Candidate objects to your context so that the template can use it.

class ElectionOfficeDetailView(DetailView):
    model = Election
    context_object_name = "election"

    def get_context_data(self, **kwargs):
        context = super(ElectionOfficeDetailView, self).get_context_data(**kwargs)
        # At this point, the context contains the 'election' object
        election = context['election']
        # Add the 'office_candidates' to the context and use in the
        # template.
        #   {% for candidate in office_candidates %}
        #       candidate
        #   {% endfor %}
        context['office_candidates'] = election.get_office_candidates(kwargs['office_id'])
        return context

@mitchdowney
Copy link
Member Author

Wow, thank you Suriya. Your explanation is very clear, but I tried it and am receiving this error:

KeyError at /elections/1/office/1
...in get_context_data

Can you help me understand why that error is happening? I apologize, I have only been coding since this July, so there are many things I don't understand...

urls.py

url(r'^elections/(?P<pk>\d+)/office/(?P<office_id>\d+)/$', ElectionOfficeDetailView.as_view(
    model=Election,
    template_name='election_detail_by_office.html',
    context_object_name='election'),
    name='election_detail_by_office',
    ),

models.py

class Election(models.Model):
    constituency = models.ForeignKey(Constituency)
    name = models.CharField(max_length=50)
    offices = models.ManyToManyField(Office, blank=True, null=True)

    def get_office_candidates(self, office_id):
        office_candidates = self.candidate_set.filter(office_id=office_id)

    return office_candidates

and I used exactly your code for views.py

Thank you very much again. This issue has been vexing me for a while.

@suriya
Copy link

suriya commented Sep 6, 2013

There needs to a minor change.

--- a.py    2013-09-06 11:48:01.555280223 +0530
+++ b.py    2013-09-06 13:33:10.901188387 +0530
@@ -11,5 +11,5 @@
         #   {% for candidate in office_candidates %}
         #       candidate
         #   {% endfor %}
-        context['office_candidates'] = election.get_office_candidates(kwargs['office_id'])
+        context['office_candidates'] = election.get_office_candidates(self.kwargs['office_id'])
         return context

Here's the correct version (I hope)

class ElectionOfficeDetailView(DetailView):
    model = Election
    context_object_name = "election"

    def get_context_data(self, **kwargs):
        context = super(ElectionOfficeDetailView, self).get_context_data(**kwargs)
        # At this point, the context contains the 'election' object
        election = context['election']
        # Add the 'office_candidates' to the context and use in the
        # template.
        #   {% for candidate in office_candidates %}
        #       candidate
        #   {% endfor %}
        context['office_candidates'] = election.get_office_candidates(self.kwargs['office_id'])
        return context

@mitchdowney
Copy link
Member Author

It works, amazing! Thank you Suriya, this is a huge help. I was stumped on this for a few days.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants