Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CBV CreateView limit ForeignKey based on get_initial()

I have two apps, family and person. In Person class, I would like to limit the available mother and father choices to those objects already created of the same family. If I could make use of the family_pk I set in get_initial() in person/views.py:PersonCreateview, and use that family_pk to restrict the ForeignKey choices of mother and father that seems like it could be a great way to group logic. Is this possible?

family/models.py

class Family(models.Model):
    lastname=models.CharField(max_length=100)

    def __str__(self):
        return self.lastname

family.views.py

from django.views import generic
from django.core.urlresolvers import reverse

from .models import Family

class FamilyListView(generic.ListView):
    context_object_name='family_list'
    model=Family


class FamilyDetailView(generic.DetailView):
    context_object_name='family'
    model=Family
    pk_url_kwarg='family_pk'


class FamilyCreateView(generic.CreateView):
    model=Family

    def get_success_url(self,**kwargs):
        return reverse('family-detail',kwargs={'family_pk':self.object.pk})

person/models.py

class Person(models.Model):
    fields=('family','firstname','mother','father')
    family=models.ForeignKey(Family)
    firstname=models.CharField(max_length=100)
    mother=models.ForeignKey('self',blank=True,null=True)
    father=models.ForeignKey('self',blank=True,null=True)

    def __str__(self):
        return self.firstname

person/views.py

from django.views import generic
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404

from .models import Person
from family.models import Family

class PersonDetailView(generic.DetailView):
    model=Person
    pk_url_kwarg='person_pk'

class PersonCreateView(generic.CreateView):
    model=Person

    def get_initial(self):
        family=get_object_or_404(Family,pk=self.kwargs.get('family_pk'))
        return {'family':family,}

    def get_success_url(self,**kwargs):
        return reverse('family:family-detail',args=[self.kwargs['family_pk']])
like image 712
Jeremiah Avatar asked Sep 05 '13 01:09

Jeremiah


1 Answers

This is perhaps a bit old, but I found a solution via this answer: https://stackoverflow.com/a/291968/1971587

The way I ended up making it work was actually with get_form(). So in your case I believe something like this would work:

class PersonCreateView(generic.CreateView):
    model = Person

    def get_family(self):
        return get_object_or_404(Family, pk=self.kwargs.get('family_pk'))

    def get_form(self, form_class):
        form = super(generic.CreateView, self).get_form(form_class)
        family = self.get_family()
        form.fields['mother'].queryset = Person.objects.filter(family)
        form.fields['father'].queryset = Person.objects.filter(family)
        return form

    def get_initial(self):
        initial = super(generic.CreateView, self).get_initial()
        initial['family'] = self.get_family()
        return initial

    def get_success_url(self, **kwargs):
        return reverse('family:family-detail', args=[self.kwargs['family_pk']])
like image 173
Joey Wilhelm Avatar answered Oct 15 '22 16:10

Joey Wilhelm