Reputation: 1071
One of my models contains a ForeignKey-field to a model that has multiple thousand instances.
When I display a record, all of these are loaded into a dropdown, which I a) don't need and b) is slow as frack, especially when displaying multiple records on one page.
Page size shoots up to multiples of 3.5mb because of the size of the dropdown.
I thought about using "limit_choices_to" to contain that, but
country = models.IntegerField(blank=True, null=True)
location = models.ForeignKey(Geonames, limit_choices_to = {'cowcode': country}, related_name='events')
does not work. Is there even a way to do that?
Update:
What do I want to display?
I want to show all places (Geonames
) that are in the country
of the EventRecord
that the code above is taken from. I want to show only these places, not the whole list of all possible places.
Why don't I need all places?
a) Page load times: 3.5 minutes for a page load is a tad too long
b) See above: An Event takes place in a certain country, so I don't need to show locations that are not in that country
Upvotes: 1
Views: 2944
Reputation: 1289
What you want is to make limit_choices_to
aware to your instance, which is not possible.
What you should do is set the queryset
property of location
field in your admin form, something similar to this:
class EventRecordAdminForm(forms.ModelForm):
class Meta:
model = EventRecord
def __init__(self, *args, **kwargs):
super(EventRecordAdminForm, self).__init__(*args, **kwargs)
self.fields['location'].queryset = Geonames.objects.filter(cowcode=self.instance.country)
and of course use that form for your admin:
class EventRecordAdmin(admin.ModelAdmin):
form = EventRecordAdminForm
See here for docs
HTH!
Upvotes: 5
Reputation: 14230
Not sure why that is not working for you. But I think a better solution would be to use django-smart-selects
. That way you can have the user choose country first. Then the Geoname dropdown is only populated when the user first chooses country.
From the docs:
If you have the following model:
class Location(models.Model)
continent = models.ForeignKey(Continent)
country = models.ForeignKey(Country)
area = models.ForeignKey(Area)
city = models.CharField(max_length=50)
street = models.CharField(max_length=100)
And you want that if you select a continent only the countries are available that are located on this continent and the same for areas you can do the following:
from smart_selects.db_fields import ChainedForeignKey
class Location(models.Model)
continent = models.ForeignKey(Continent)
country = ChainedForeignKey(
Country,
chained_field="continent",
chained_model_field="continent",
show_all=False,
auto_choose=True
)
area = ChainedForeignKey(Area, chained_field="country", chained_model_field="country")
city = models.CharField(max_length=50)
street = models.CharField(max_length=100)
This example asumes that the Country Model has a continent = ForeignKey(Continent) field and that the Area model has country = ForeignKey(Country) field.
Upvotes: 0
Reputation: 1829
if you are using admin interface you can use raw_id_fields in ModelAdmin:
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'publisher', 'publication_date')
list_filter = ('publication_date',)
date_hierarchy = 'publication_date'
ordering = ('-publication_date',)
filter_horizontal = ('authors',)
raw_id_fields = ('publisher',)
sometimes you don’t want to incur the overhead of having to select all the related objects to display in the drop-down. For example, if our book database grows to include thousands of publishers, the “Add book” form could take a while to load, because it would have to load every publisher for display in the box.
The way to fix this is to use an option called raw_id_fields. Set this to a tuple of ForeignKey field names, and those fields will be displayed in the admin with a simple text input box () instead of a select.
Upvotes: 2