1. ホーム
  2. パイソン

[解決済み] DjangoのモデルフォームでForeignKeyの選択肢をフィルタリングするにはどうすればよいですか?

2022-04-21 15:01:11

質問

例えば、以下のような models.py :

class Company(models.Model):
   name = ...

class Rate(models.Model):
   company = models.ForeignKey(Company)
   name = ...

class Client(models.Model):
   name = ...
   company = models.ForeignKey(Company)
   base_rate = models.ForeignKey(Rate)

すなわち、複数の Companies の範囲を持ち、それぞれが RatesClients . それぞれ Client は、ベースとなる Rate 親から選ばれた Company's Rates でなく、別の Company's Rates .

を追加するためのフォームを作成する場合 Client を削除したい。 Company のボタンで既に選択されているため)。 Company ページ)を制限し Rate の選択肢は、その Company もあります。

Django 1.0ではどうすればいいのでしょうか?

私の現在の forms.py ファイルは、今のところ単なるボイラープレートです。

from models import *
from django.forms import ModelForm

class ClientForm(ModelForm):
    class Meta:
        model = Client

そして views.py も基本です。

from django.shortcuts import render_to_response, get_object_or_404
from models import *
from forms import *

def addclient(request, company_id):
    the_company = get_object_or_404(Company, id=company_id)

    if request.POST:
        form = ClientForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(the_company.get_clients_url())
    else:
        form = ClientForm()

    return render_to_response('addclient.html', {'form': form, 'the_company':the_company})

Django 0.96 では、テンプレートをレンダリングする前に以下のようなことをすることで、これをハックすることができました。

manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]

ForeignKey.limit_choices_to は期待できそうですが、どのようにして the_company.id というのも、Admin インターフェイスの外側でそれが機能するかどうかがわからないからです。

ありがとうございます。 (これはかなり基本的な要求のようですが、もし私が何かをデザインし直すべきなら、提案を受け付けます)

どのように解決するのですか?

ForeignKey は django.forms.ModelChoiceField で表現され、これは選択肢をモデルの QuerySet とする ChoiceField です。 のリファレンスを参照してください。 ModelChoiceField .

そこで、QuerySetをフィールドの queryset 属性で指定します。 フォームの構築方法によります。 明示的なフォームを構築する場合は、フィールドの名前を直接指定することになります。

form.rate.queryset = Rate.objects.filter(company_id=the_company.id)

デフォルトのModelFormオブジェクトを取る場合。 form.fields["rate"].queryset = ...

これは、ビューで明示的に行われます。 ハックする必要はありません。