Adding more data to Generic Views

131 views
Skip to first unread message

Lachlan Musicman

unread,
Jul 31, 2012, 12:17:26 AM7/31/12
to django...@googlegroups.com
Hola,

I'm confused about adding extra content to a class based Generic View. I've read
the docs at file:///home/datakid/src/django-docs/topics/class-based-views.html 
and have written the code accordingly. 

I have Person, Certificate, Job and Compensation objects. The last three all 
have an FK (or M2M) back to a (or some) Person(s).

My DetailView subclass (which I've put in views.py - is there a better or more
correct place for it?)

class PersonDetailView(DetailView):
    context_object_name = "person"
    model = Person

    def get_context_data(self,**kwargs):
        #Call the base implementation first to get a context
        context = super(PersonDetailView, self).get_context_data(**kwargs)
        #Add in a querysets
        context['job_list'] = Vacancy.complete.all()
        context['certificate_list'] = Certificate.objects.all()
        context['claim_list'] = Compensation.objects.all()
        return context

But I don't want the full list of Vacancies, Certificates or Claims - I just 
want those that are linked to the person - how can I filter by these? I've tried
.filter(self.get_id)
.filter(self.request.get_id)
.filter(self.person.get_id)
.filter(self.request.person.get_id)
.filter(applicants__get_id__exact=self.get_id) (in the case of Vacancy) etc

How do I filter by the person object that is already in the context?
I know the answer is simple - I should wait until tomorrow when my brain is 
fresher, but I want to finish this off tonight if possible.

Of course, the other thing that I can't help but thinking is that at this point, the non-generic-view method of urls/views might be a simpler way to go. While Generic Views are quite versatile,  is there a point at which they are considered to restricting? 

L.

Per-Olof Åstrand

unread,
Jul 31, 2012, 5:07:10 AM7/31/12
to django...@googlegroups.com
Hi,

I just started to convert my small hobby-project into class-based views and struggled with similar things (but with a ListView instead).

The person object is in the context dictionary, so you need to refer to it by context['person'].

More generally, it is instructive to print context, kwargs and self.kwargs inside the get_context_data method. That would give you the information you need. It took me some time to realize that url-captured parameters are available in self.kwargs.

Per-Olof

Karl Sutt

unread,
Jul 31, 2012, 7:15:50 AM7/31/12
to django...@googlegroups.com
So, in conclusion, Lachlan, you would want to do something like:

 def get_context_data(self,**kwargs):
        #Call the base implementation first to get a context
        context = super(PersonDetailView, self).get_context_data(**kwargs)
        #Add in a querysets
        context['job_list'] = Vacancy.complete.filter(person_id=self.kwargs[self.pk_url_kwarg])
        context['certificate_list'] = Certificate.objects.filter(person_id=self.kwargs[self.pk_url_kwarg])
        context['claim_list'] = Compensation.objects.filter(person_id=self.kwargs[self.pk_url_kwarg])
        return context

I have not tested this, but it gives you the idea. You'll want to filter the Vacancy, Certificate and Compensation objects by the person's ID. 

Good luck

Tervitades/Regards
Karl Sutt


--
You received this message because you are subscribed to the Google Groups "Django users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/6O_nqDwvAAEJ.

To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Melvyn Sopacua

unread,
Jul 31, 2012, 8:43:09 AM7/31/12
to django...@googlegroups.com
On 31-7-2012 6:17, Lachlan Musicman wrote:

> I have Person, Certificate, Job and Compensation objects. The last three
> all
> have an FK (or M2M) back to a (or some) Person(s).
>

So reverse relations.

> def get_context_data(self,**kwargs):
> #Call the base implementation first to get a context
> context = super(PersonDetailView, self).get_context_data(**kwargs)
> #Add in a querysets
> context['job_list'] = Vacancy.complete.all()
> context['certificate_list'] = Certificate.objects.all()
> context['claim_list'] = Compensation.objects.all()

You don't need any of these. In your template, simply call:
{{ person.certificate_set.fieldname }}

If you insist on having them available as you do above, they should be:
context['job_list'] = self.get_object().vacancy_set.all()
context['certificate_list'] = self.get_object().certificate_set.all()
context['claim_list'] = self.get_object().compensation_set.all()

Required reading:
https://docs.djangoproject.com/en/1.4/ref/models/relations/

Also, skipping the tutorial is not recommended:
<https://docs.djangoproject.com/en/1.4/intro/tutorial03/#use-the-template-system>

> Of course, the other thing that I can't help but thinking is that at this
> point, the non-generic-view method of urls/views might be a simpler way to
> go. While Generic Views are quite versatile, is there a point at which
> they are considered to restricting?

Not really. The only thing that bugs me about them is that adding extra
context requires sub-classing so you end up with a views.py that solely
consists of sub-classed generic views with 3 lines of get_context_data().
--
Melvyn Sopacua

Lachlan Musicman

unread,
Jul 31, 2012, 4:20:37 PM7/31/12
to django...@googlegroups.com
On Tue, Jul 31, 2012 at 11:15 PM, Karl Sutt <ka...@sutt.ee> wrote:
So, in conclusion, Lachlan, you would want to do something like:

 def get_context_data(self,**kwargs):
        #Call the base implementation first to get a context
        context = super(PersonDetailView, self).get_context_data(**kwargs)
        #Add in a querysets
        context['job_list'] = Vacancy.complete.filter(person_id=self.kwargs[self.pk_url_kwarg])
        context['certificate_list'] = Certificate.objects.filter(person_id=self.kwargs[self.pk_url_kwarg])
        context['claim_list'] = Compensation.objects.filter(person_id=self.kwargs[self.pk_url_kwarg])
        return context

I have not tested this, but it gives you the idea. You'll want to filter the Vacancy, Certificate and Compensation objects by the person's ID. 

Great - thanks!

L, 

Lachlan Musicman

unread,
Jul 31, 2012, 4:45:26 PM7/31/12
to django...@googlegroups.com
On Wed, Aug 1, 2012 at 12:43 AM, Melvyn Sopacua <m.r.s...@gmail.com> wrote:
On 31-7-2012 6:17, Lachlan Musicman wrote:

> I have Person, Certificate, Job and Compensation objects. The last three
> all
> have an FK (or M2M) back to a (or some) Person(s).
>

So reverse relations.

Yep, thanks - with Django I often find I have an idea in my head but don't know what to call it - and it's often surprising what the developers do call it, until it makes perfect sense . I'm still waiting for that eureka moment with reverse urls tbh - I have read the docs on those a dozen times, and just do not get why they are useful or when you would use them. I guess I need a local example.
 
>     def get_context_data(self,**kwargs):
>         #Call the base implementation first to get a context
>         context = super(PersonDetailView, self).get_context_data(**kwargs)
>         #Add in a querysets
>         context['job_list'] = Vacancy.complete.all()
>         context['certificate_list'] = Certificate.objects.all()
>         context['claim_list'] = Compensation.objects.all()

You don't need any of these. In your template, simply call:
{{ person.certificate_set.fieldname }}

Yes, I was doing that originally (when there was no Compensation objects), but I was struggling with only rendering when a set existed - for example, in my person_detail.html I was rendering from the wrong direction - via the non-Person object via "related name" fields on the FK.

        {% if person.jobs %}
        <h3>Jobs Applied For</h3>
        {% for job in person.jobs.all %}
        <p>
        <a href="{{ job.get_absolute_url }}">{{ job.title }}, <em>{{ job.organisation }}{% if job.division %}, {{ job.division }}{% endif %}</em></a>
        </p>
 
Which gives me the problem that I was *actually* trying to solve - how to only render "Jobs Applied For" - the reason for the if statement - if jobs have been applied for by that person. It didn't work. 

I will try using person.vacancy_set.all now ...

 
If you insist on having them available as you do above, they should be:
context['job_list'] = self.get_object().vacancy_set.all()
context['certificate_list'] = self.get_object().certificate_set.all()
context['claim_list'] = self.get_object().compensation_set.all()

Required reading: 
https://docs.djangoproject.com/en/1.4/ref/models/relations/

Also, skipping the tutorial is not recommended:
<https://docs.djangoproject.com/en/1.4/intro/tutorial03/#use-the-template-system>

I didn't, but I did only skim it, since I've done it before.

> Of course, the other thing that I can't help but thinking is that at this
> point, the non-generic-view method of urls/views might be a simpler way to
> go. While Generic Views are quite versatile,  is there a point at which
> they are considered to restricting?

*too*
 
Not really. The only thing that bugs me about them is that adding extra
context requires sub-classing so you end up with a views.py that solely
consists of sub-classed generic views with 3 lines of get_context_data().

Ok, thanks. I'm still confused about the usefulness of subclassing, given that object_set exists? I presuming it's to have the actual objects in the context, not just a reference to them?

anyway, thanks for hte help
L.
 

Lachlan Musicman

unread,
Jul 31, 2012, 10:11:43 PM7/31/12
to django...@googlegroups.com
On Wed, Aug 1, 2012 at 8:45 AM, Lachlan Musicman <dat...@gmail.com> wrote:
On Wed, Aug 1, 2012 at 12:43 AM, Melvyn Sopacua <m.r.s...@gmail.com> wrote:
On 31-7-2012 6:17, Lachlan Musicman wrote:

> I have Person, Certificate, Job and Compensation objects. The last three
> all
> have an FK (or M2M) back to a (or some) Person(s).
>
You don't need any of these. In your template, simply call:
{{ person.certificate_set.fieldname }}
I will try using person.vacancy_set.all now ...

Ok - this only works for FK relationships, not for M2M relationships?

cheers
L.  

Melvyn Sopacua

unread,
Aug 2, 2012, 5:04:40 PM8/2/12
to django...@googlegroups.com
On 31-7-2012 22:45, Lachlan Musicman wrote:

> Yes, I was doing that originally (when there was no Compensation objects),
> but I was struggling with only rendering when a set existed - for example,
> in my person_detail.html I was rendering from the wrong direction - via the
> non-Person object via "related name" fields on the FK.
>
> {% if person.jobs %}

{% if person.jobs.count %}

person.jobs always exists as it is the related manager. If count is zero
the if statement resolves to false.

> Ok, thanks. I'm still confused about the usefulness of subclassing, given
> that object_set exists? I presuming it's to have the actual objects in the
> context, not just a reference to them?

No, it's primarily useful to provide data that have no relation to the
model you're presenting. Like "today's shoe discounts" displayed on the
"blue women pants" page are unrelated models (from a technical
perspective ;) ).
Another example is if you want to pass some parameters by query string
to only a few pages, but otherwise in the site don't use the request
context processor [1]:

def get_context_data(self, **kwargs) :
context = super(MyView, self).get_context_data(**kwargs)
context['qs'] = self.request.GET
return context

[1]
<https://docs.djangoproject.com/ref/templates/api.html#subclassing-context-requestcontext>
--
Melvyn Sopacua
Reply all
Reply to author
Forward
0 new messages