2009-06-11 11 views
13

私は、40,000行のモデルのForeignKey値である1つのフィールドを持つモデルフォームを持っています。デフォルトのmodelformは、40,000個のオプションを持つ選択ボックスを作成しようとします。このモデルフォームがフォームセットファクトリで使用されているときは、さらにそうです!モデルフォームのraw_id_fields

管理者は、これは "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

は、ここに私のModelFormです。 base "は" Base "インスタンスでなければなりません。モデルフォームを保存するには、 'base'がBaseインスタンスである必要があります。明らかに、基本主キーの文字列表現では(少なくとも自動的には)十分ではありません。フォームに与えられた文字列をBaseインスタンスに変更するためには、何らかのメカニズムが必要です。そして、このメカニズムはformsetで動作しなければなりません。何か案は? raw_id_fieldsしか動作しない場合、これはケーキとして簡単になります。しかし、私が知る限り、管理者だけが利用可能です。

答えて

10

フィールドタイプではなくbaseフィールドのウィジェットを変更する必要があります。私はこれが仕事だと思う:

class OpBaseForm(ModelForm): 
    base = forms.ModelChoiceField(queryset=Base.objects.all(), 
            widget=forms.TextInput) 

    class Meta: 
     model = OpBase 
     ... etc... 
+1

明確にするために、raw_id_field属性はModelAdmin属性です。http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields ModelForm属性ではありません。 –

13

あなたはまた、管理ページがあり便利JSポップアップ検索との完全な全体raw_id_field管理ウィジェットを使用することができます。モデル・フォームは必要ありません。

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)) 

があなたのテンプレートに関連する管理JSを追加し、上記ヴォルテールさんのコメントに展開するにはヴィオラ

{% 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

Django 1.4では、ForeignKeyRawIdWidgetのコンストラクタが変更されたように見えます。このコードを使用すると、__init __()は3つの引数(2が指定されています)を返します。 django.contrib.adminをインポートした場合は、欠落している引数としてadmin.siteを直接ForeignKeyRawIdWidgetに渡し、HardcodedUrlバージョンでラップする必要はありません。 – Voltaire

+0

この作業を行うには 'admin.autodiscover()'が必要です。私は答えにこれを書いています。少し欠けているからです。 – chriscauley

+0

管理者にリダイレクトしたくない場合はどうすればよいですか? – thumbtackthief

12

は、ジャンゴ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にはクエリーセットが必要ですが、実際には使用されません。 CharFieldが正しく検証されないので(Modelインスタンスを参照するのではなくIDを保存しようとするため)、ModelChoiceFieldはCharFieldよりも優先されます。

+0

管理サイトにリダイレクトせずにこれを行う方法はありますか?理想的には、jqueryの自動補完機能のようなものですか? – thumbtackthief

関連する問題