はじめに
マスタ参照してるリストボックスについて、ログインユーザーの権限に応じて選択可能なアイテムを制御したい…というケースが発生。
↓のモデルとフォームをサンプルに、調べて試してみたやり方のメモ。
models.py
class Book(models.Model):
name = models.charField('name',max_length=255)
forms.py
class SampleForm(forms.Form):
book = forms.ModelChoiceField(label='book',queryset=Book.objects.all())
フォーム生成後にquerysetを上書きする
たぶん、一番シンプルな方法。
form = SampleForm()
form.fields['book'].queryset = Book.objects.filter(...)
フォームの__init__
でquerysetを引数に受け取って上書きする
forms.py
class SampleForm(forms.Form):
book = forms.ModelChoiceField(label='book',queryset=Book.objects.none())
def __init__(self, queryset=None, *args, **kwargs):
super(SampleForm,self).__init__(*args,**kwargs)
if queryset :
self.fields['book'].queryset = queryset
form = SampleForm(queryset=Book.objects.filter(...))
super.__init__
をコールしないと、self.fields
が生成されないので注意。
デフォルトのquerysetどうするかは、フォームの役割次第。
querysetそのものを受け取らず、フィルタの条件に使うデータだけ受け取っておいて、querysetの生成はフォーム側で行う…という実装でも可。
forms.py
class SampleForm(forms.Form):
book = forms.ModelChoiceField(label='book',queryset=Book.objects.none())
def __init__(self, permission=None, *args, **kwargs):
super(SampleForm,self).__init__(*args,**kwargs)
self.fields['book'].queryset = self.get_book_list(permission)
def get_book_list(self, permission=None):
if not permission :
return Book.objects.none()
if permission == AAA :
query = Q(...)
elif permission == BBB :
query = Q(...)
# 必要なだけ処理書く...
return Book.objects.filter(query)
本質的にやってることは同じ。
要は、Form.__init__
の処理が終わってから、Form.fields['field_name'].queryset
を上書きすればいい。
余談
Form.fields
をいじれば、他のフィールドのいろんな属性をフォーム生成後に変更することができる。
フィールドそのものを追加・削除することもできるかも?