장고 ModelForm 을 편하게 쓰고 있는데, 아예 입력 창을 띄울 때 Foreign key로 등록된 필드를 일부 필터링해서 보여주고 싶은 경우가 아주 자주 발생한다. 무슨 overring 하면 될 듯 한데 솔루션을 찾아보자.
(2021.11.25) 업데이트
request.POST 데이터를 넘기니깐, 첫번째 인자로 들어가 버려서 원래 작성된 아래 글처럼 선언하면 사용자 변수 위치에 떡 들어가 버려서 오류를 일으킴.
그냥 아래처럼 사용자 변수를 받도록 처리하자. 인자를 추가하지 말고
참고 사이트 - https://europani.tistory.com/247
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user') # pop을 이용하여 받음
super().__init__(*args, **kwargs)
머니머니 해도 구글링이 최고고 stackoverflow (한국의 네이버 지식인은 왜....) 가 최고인듯 하다
검색을 해보니 아래 글이 나온다.
https://stackoverflow.com/questions/48126151/django-modelform-foreign-key-filtering
말인 즉슨
__init__ 함수를 오버라이딩 해라는 것!!
form.py 의 코드에서
from django import forms
from .models import Album, Song
class SongCreateForm(forms.ModelForm):
class Meta:
model = Song
fields = [
'album',
'name',
'is_favorite'
]
def __init__(self, user, *args, **kwargs):
super(SongCreateForm, self).__init__(*args, **kwargs)
self.fields['album'].queryset = Album.objects.filter(owner=user)
여기에 보는 바와 같이 album 이라는 외부키 참조 필드를 필터링 하는 코드가 __init__ 오버라이딩 함수에 들어가 있다.
아무거나 보여주지 않고 폼을 띄울때 특정 사용자 앨범만 가져오는 코드를 넣어 두는 것이다.
당연히 매개변수에는 user를 받아 와야 한다. 즉,
그럼 이 Form 을 불러주는 view 함수에서 어떻게 호출해야 하는지 알아보자.
from django.views.generic import CreateView
class SongCreateView(CreateView):
success_url = '/songs/'
def get_form(self, form_class=None):
form_class = SongCreateForm(user=self.request.user)
...
위의 코드 처럼 폼을 호출할 때 user 라는 파라미터를 같이 넣어서 불러주면 된다.
그럼 __init__ 함수에서 이 변수를 받아 정의된 문장에 의해 필터링이 되고,
fiels['album'] 은 필터링 된 값만 가지고 보여주도록 할 수 있다.
(추가)
아래 처럼 기본 값을 넣어 두면, 호출 할 때 이 매개변수를 쓰지 않아도 정상동작 한다.
아래 처럼 하지 않으면 매번 호출 할 때 마다 꼭 user 라는 매개변수를 넣어 줘야 한다.
def __init__(self, user=None, *args, **kwargs):
super(ItemForm, self).__init__(*args, **kwargs)
if user is not None:
self.fields['album'].queryset = ....
Andrea Piacquadio 님의 사진, 출처: Pexels