Re: Definitive solution for foreignkey filtering in Admin

2009-11-05 Thread Tim Valenta

After considering the severe disadvantage imposed by lacking a
handling case for the 'add' view, I figured it out and wrote it up
here, for the sake of more verbose documentation:

http://mangos.dontexist.net/blog/?p=345

Primarily, the idea is that for inlines, I can grab the hidden field
providing the id of the primary parent field.  Using that id I can
traverse up to the parent, and then back down to filter options
accordingly.  For non-inline 'add' view cases, this is still an issue,
but if you can fill out enough required fields, you can actually do
something like the following:

class MyInlineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
forms.ModelForm.__init__(self, *args, **kwargs)
if 'instance' in kwargs:
instance = kwargs['instance']
else:
instance = MyParentModel.objects.get(pk=tuple(i[0] for i
in form.fields['myparentmodel'].widget.choices)[1])
self.fields['othermodel'].queryset = OtherModel.objects.filter
(parent=instance)

Sorry if the abstraction to generic names is hard to read.  Basically
you get into the 'choices' on the hidden field (which are oddly still
fully assembled, with u'' and all) and grab the only id in the
list, using it to look up the proper model.  You could forgo the
actual model lookup, and just filter OtherModel by a lookup to the id
only, but in complex cases like my own (I've only touched the surface
with the Company-Contract-Location scenario) I need the model instance
itself.

Tim

On Nov 5, 4:37 pm, Tim Valenta  wrote:
> I don't know what changed, but updating my SVN in the last week
> sometime has fixed the problem that I was having.
>
> The dev trunk and I have a love-hate relationship :)
>
> I would make a note to anybody reading this that if the 'add' view is
> being used, you should kick off the code block with a "if 'instance'
> in kwargs"
>
> Working code:
>
>   # used in a direct subclass of ModelAdmin
>   class ContractForm(forms.ModelForm):
>       def __init__(self, *args, **kwargs):
>           forms.ModelForm.__init__(self, *args, **kwargs)
>           if 'instance' in kwargs:
>               contract = kwargs['instance']
>               self.fields['locations'].queryset =
> Location.objects.filter(company=contract.company)
>
>   # used in a TabularInline of that same ModelAdmin's inlines
>   class EventInlineForm(forms.ModelForm):
>       def __init__(self, *args, **kwargs):
>           forms.ModelForm.__init__(self, *args, **kwargs)
>           if 'instance' in kwargs:
>               contract = kwargs['instance']
>               self.fields['location'].queryset =
> Location.objects.filter(company=contract.company)
>
> Thank you, God.  I've been pulling my hair out over this.
>
> Tim
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: Definitive solution for foreignkey filtering in Admin

2009-11-05 Thread Tim Valenta

I don't know what changed, but updating my SVN in the last week
sometime has fixed the problem that I was having.

The dev trunk and I have a love-hate relationship :)


I would make a note to anybody reading this that if the 'add' view is
being used, you should kick off the code block with a "if 'instance'
in kwargs"

Working code:

  # used in a direct subclass of ModelAdmin
  class ContractForm(forms.ModelForm):
  def __init__(self, *args, **kwargs):
  forms.ModelForm.__init__(self, *args, **kwargs)
  if 'instance' in kwargs:
  contract = kwargs['instance']
  self.fields['locations'].queryset =
Location.objects.filter(company=contract.company)

  # used in a TabularInline of that same ModelAdmin's inlines
  class EventInlineForm(forms.ModelForm):
  def __init__(self, *args, **kwargs):
  forms.ModelForm.__init__(self, *args, **kwargs)
  if 'instance' in kwargs:
  contract = kwargs['instance']
  self.fields['location'].queryset =
Location.objects.filter(company=contract.company)

Thank you, God.  I've been pulling my hair out over this.

Tim
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: Definitive solution for foreignkey filtering in Admin

2009-10-26 Thread Tim Valenta

> forms.ModelForm.__init__(self, *args, **kwargs)
> location = kwargs.get('instance', None)
> if location:
> self.fields['contract'].queryset = Contract.objects.filter
> (company=location.company)

It seems that editing the values in self.fields yields rendering
errors:

Caught an exception while rendering: 'QuerySet' object has no
attribute 'label'

It appears that the values are not vanilla QuerySets... I've been
browsing the code again, and I really don't know what the values are.
It's fairly convoluted with that __metaclass__ business in there.  Do
we know what kind of datatype is in self.fields?  When the template
iterates the Form object, it's wrapping it as a BoundField, but
clearly something's messing up during that iteration.  I'm afraid I
don't know much about how the mechanics of this area work in the
Python code.

Any more pointers would be great.  Other than this speedbump, I think
this will do nicely.

Tim

On Oct 26, 8:53 am, Tim Valenta  wrote:
> Many many thanks for the response.
>
> I had tried that approach, but had no idea what was coming through in
> kwargs.  I feel like 'kwargs' on most class objects needs more
> thorough documentation for the general users who refer primarily to
> the on-site docs.  Even digging through some code, I simply had no
> idea.
>
> This should provide a working fix for the sort of filtering I need to
> do.  I hope that maybe I or some other person can provide some code to
> help simplify this amazingly common dilemma.  Any models that group in
> logical relationships of 3 seem to always have this problem, and I'd
> love to have a simpler fix to write off in the docs.
>
> Tim
>
> On Oct 25, 8:28 pm, Matt Schinckel  wrote:
>
>
>
> > On Oct 24, 5:14 am, Tim Valenta  wrote:
>
> > > I've been searching for a while on how to intercept querysets in
> > > forms, to apply a custom filter to the choices on both foreignkey and
> > > m2m widgets.  I'm surprised at how there are so many similar questions
> > > out there, dating back to 2006.
>
> > [snip]
>
> > > The only solution I've seen has dealt with filtering by User foreign
> > > key (being that User is available in the request object in views), and
> > > that's primarily for non-Admin views.
>
> > [snip]
>
> > > I've been looking at the code for the above noted API method,
> > > formfield_for_foreignkey, and I really can't see a way to get
> > > references to an instance of the object being edited.  I would need
> > > such a reference to successfully override that method and filter my
> > > queryset on this relationship.
>
> > I too spent some time looking at formfield_for_foreignkey, and had no
> > luck.
>
> > You can subclass ModelAdmin, and then limit the objects in the field's
> > queryset.
>
> > ** admin.py **
>
> > class LocationAdminForm(forms.ModelForm):
> >     def __init__(self, *args, **kwargs):
> >         forms.ModelForm.__init__(self, *args, **kwargs)
> >         location = kwargs.get('instance', None)
> >         if location:
> >             self.fields['contract'].queryset = Contract.objects.filter
> > (company=location.company)
>
> > class LocationAdmin(admin.ModelAdmin):
> >     model = Location
> >     form = LocationAdminForm
>
> > I also had to do something similar with Inlines, when I did the same
> > type of thing.  This is not my exact code, but it is very close, and
> > suited toward your use case.
>
> > Matt.
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: Definitive solution for foreignkey filtering in Admin

2009-10-26 Thread Tim Valenta

Many many thanks for the response.

I had tried that approach, but had no idea what was coming through in
kwargs.  I feel like 'kwargs' on most class objects needs more
thorough documentation for the general users who refer primarily to
the on-site docs.  Even digging through some code, I simply had no
idea.

This should provide a working fix for the sort of filtering I need to
do.  I hope that maybe I or some other person can provide some code to
help simplify this amazingly common dilemma.  Any models that group in
logical relationships of 3 seem to always have this problem, and I'd
love to have a simpler fix to write off in the docs.

Tim

On Oct 25, 8:28 pm, Matt Schinckel  wrote:
> On Oct 24, 5:14 am, Tim Valenta  wrote:
>
> > I've been searching for a while on how to intercept querysets in
> > forms, to apply a custom filter to the choices on both foreignkey and
> > m2m widgets.  I'm surprised at how there are so many similar questions
> > out there, dating back to 2006.
>
> [snip]
>
> > The only solution I've seen has dealt with filtering by User foreign
> > key (being that User is available in the request object in views), and
> > that's primarily for non-Admin views.
>
> [snip]
>
> > I've been looking at the code for the above noted API method,
> > formfield_for_foreignkey, and I really can't see a way to get
> > references to an instance of the object being edited.  I would need
> > such a reference to successfully override that method and filter my
> > queryset on this relationship.
>
> I too spent some time looking at formfield_for_foreignkey, and had no
> luck.
>
> You can subclass ModelAdmin, and then limit the objects in the field's
> queryset.
>
> ** admin.py **
>
> class LocationAdminForm(forms.ModelForm):
>     def __init__(self, *args, **kwargs):
>         forms.ModelForm.__init__(self, *args, **kwargs)
>         location = kwargs.get('instance', None)
>         if location:
>             self.fields['contract'].queryset = Contract.objects.filter
> (company=location.company)
>
> class LocationAdmin(admin.ModelAdmin):
>     model = Location
>     form = LocationAdminForm
>
> I also had to do something similar with Inlines, when I did the same
> type of thing.  This is not my exact code, but it is very close, and
> suited toward your use case.
>
> Matt.
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Re: Definitive solution for foreignkey filtering in Admin

2009-10-25 Thread Matt Schinckel

On Oct 24, 5:14 am, Tim Valenta  wrote:
> I've been searching for a while on how to intercept querysets in
> forms, to apply a custom filter to the choices on both foreignkey and
> m2m widgets.  I'm surprised at how there are so many similar questions
> out there, dating back to 2006.

[snip]

> The only solution I've seen has dealt with filtering by User foreign
> key (being that User is available in the request object in views), and
> that's primarily for non-Admin views.

[snip]

> I've been looking at the code for the above noted API method,
> formfield_for_foreignkey, and I really can't see a way to get
> references to an instance of the object being edited.  I would need
> such a reference to successfully override that method and filter my
> queryset on this relationship.

I too spent some time looking at formfield_for_foreignkey, and had no
luck.

You can subclass ModelAdmin, and then limit the objects in the field's
queryset.

** admin.py **

class LocationAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
forms.ModelForm.__init__(self, *args, **kwargs)
location = kwargs.get('instance', None)
if location:
self.fields['contract'].queryset = Contract.objects.filter
(company=location.company)

class LocationAdmin(admin.ModelAdmin):
model = Location
form = LocationAdminForm


I also had to do something similar with Inlines, when I did the same
type of thing.  This is not my exact code, but it is very close, and
suited toward your use case.

Matt.
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---



Definitive solution for foreignkey filtering in Admin

2009-10-23 Thread Tim Valenta

I've been searching for a while on how to intercept querysets in
forms, to apply a custom filter to the choices on both foreignkey and
m2m widgets.  I'm surprised at how there are so many similar questions
out there, dating back to 2006.

I came across the documentation for
ModelAdmin.formfield_for_foreignkey (http://docs.djangoproject.com/en/
dev/ref/contrib/admin/
#django.contrib.admin.ModelAdmin.formfield_for_foreignkey), and
thought I had a perfect solution, but the method doesn't seem to
entirely fit the hole I'm trying to fill.

Consider these models:

# models.py
class Company(models.Model):
# ...
class Contract(models.Model):
company = models.ForeignKey(Company)
locations = models.ManyToManyField('Location')
class Location(models.Model):
company = models.ForeignKey(Company)

So, Company is at the top of the hierarchy, with both Contract and
Location holding foreign keys to Company, and then Contract and
Location share an m2m relationship.

The admin presents this data so that the m2m widget on Contract lets
you pick from any Location in the database.  Arguably, there should be
an option for the implied common relationship to take effect, of both
Contract and Location to Company.

The only solution I've seen has dealt with filtering by User foreign
key (being that User is available in the request object in views), and
that's primarily for non-Admin views.




I've been looking at the code for the above noted API method,
formfield_for_foreignkey, and I really can't see a way to get
references to an instance of the object being edited.  I would need
such a reference to successfully override that method and filter my
queryset on this relationship.

Any thoughts?  There are dozens of unanswered questions just like this
all over popular sites on the internet.  We need a solution.  The
feature list for Django 1.2 does not seem to reference anything on
this matter!

Tim
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~--~~~~--~~--~--~---