我有一个modelform,其中有一个字段是一个ForeignKey值,一个模型为40,000行。默认模型尝试创建一个包含40,000个选项的选择框,这至少是不理想的。当这个模型在formset工厂中使用时更是如此!
在管理员中,使用“raw_id_fields
”可以轻松避免这种情况,但似乎没有相应的模型形式。我怎么能这样做?
这是我的模型形式:
class OpBaseForm(ModelForm):
base = forms.CharField()
class Meta:
model = OpBase
exclude = ['operation', 'routes']
extra = 0
raw_id_fields = ('base', ) #does nothing
第一个粗体线的工作原理是没有创建庞大的笨重的选择框,但是当我尝试保存此表单的字段集时,我收到错误:“OpBase.base”必须是“Base”实例。< / strong>为了保存modelform,'base'需要是Base实例。显然,Base主键的字符串表示是不够的(至少不是自动的)。我需要某种机制来将表单给出的字符串更改为Base实例。而这种机制必须在一个formset中工作。有任何想法吗?如果只有raw_id_fields
可以工作,这就像蛋糕一样简单。但据我所知,它只在管理员中可用。
答案 0 :(得分:14)
您还可以使用整个raw_id_field管理窗口小部件,以及管理页面具有的方便的js弹出搜索。你甚至不需要模型表格。方法如下:
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))
将相关的管理员j添加到您的模板和中提琴
{% 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 %}
答案 1 :(得分:12)
为了扩展Voltaire上面的评论,django 1.4解决方案是:
from django.contrib import admin
admin.autodiscover()
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
from django import forms
from .models import Post, Photo
class PostForm(forms.ModelForm):
photo = forms.ModelChoiceField(
Photo.objects.all(),
widget=ForeignKeyRawIdWidget(Post._meta.get_field("photo").rel,admin.site)
)
您需要的唯一额外的JavaScript是:
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
这里重要的是你在管理员上调用自动发现,否则你的RawIdWidget将没有链接。此外,ModelChoiceField还需要一个实际未使用的查询集。 ModelChoiceField比CharField更可取,因为CharField没有正确验证(尝试保存id而不是查找Photo实例)。
答案 2 :(得分:11)
您需要更改base
字段的小部件,而不是字段类型。我认为这样可行:
class OpBaseForm(ModelForm):
base = forms.ModelChoiceField(queryset=Base.objects.all(),
widget=forms.TextInput)
class Meta:
model = OpBase
... etc...