Re: Definitive solution for foreignkey filtering in Admin
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 Valentawrote: > 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
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
> 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 Valentawrote: > 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
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 Schinckelwrote: > 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
On Oct 24, 5:14 am, Tim Valentawrote: > 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
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 -~--~~~~--~~--~--~---