I have a modelform which has one field that is a ForeignKey value to a model which as 40,000 rows. The default modelform tries to create a select box with 40,000 options, which, to say the least is not ideal. Even more so when this modelform is used in a formset factory!
In the admin, this is easiely avoidable by using "raw_id_fields
", but there doesn't seem to be a modelform equivalent. How can I do this?
Here is my modelform:
class OpBaseForm(ModelForm):
base = forms.CharField()
class Meta:
model = OpBase
exclude = ['operation', 'routes']
extra = 0
raw_id_fields = ('base', ) #does nothing
The first bolded line works by not creating the huge unwieldy selectbox, but when I try to save a fieldset of this form, I get the error: "OpBase.base" must be a "Base" instance. In order for the modelform to be saved, 'base' needs to be a Base instance. Apparently, a string representation of a Base primary key isn't enough (at least not automatically). I need some kind of mechanism to change the string that is given my the form, to a Base instance. And this mechanism has to work in a formset. Any ideas? If only raw_id_fields
would work, this would be easy as cake. But as far as I can tell, it only is available in the admin.
You can also use the entire raw_id_field admin widget, complete with the handy js popup search that the admin page has. You don't even need a model form. Here's how:
import string
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
from django import forms
from models import MyModel
# Have to subclass widget b/c
# django hardcodes a relative path to Admin Root URL: ../../..
class HardcodedURLForeignKeyRawIdWidget(ForeignKeyRawIdWidget):
def render(self, *args, **kwargs):
original_render = super(HardcodedURLForeignKeyRawIdWidget,
self).render(*args, **kwargs)
ADMIN_ROOT_URL = "/admin/"
return string.replace(original_render,"../../../", ADMIN_ROOT_URL)
class FieldLookupForm(forms.Form):
my_foreignkey_field = forms.CharField(max_length=10,
widget=HardcodedURLForeignKeyRawIdWidget(
MyModel._meta.get_field("foreignkey_field").rel))
Add the relevant admin js to your template, and viola
{% block header %}
<script type="text/javascript">window.__admin_media_prefix__ = "/static/admin/";</script>
<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.min.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.min.js"></script>
{% endblock %}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With