미들웨어를 사용하여 외국 키로 선택을 제한합니다
-
09-09-2019 - |
문제
나는 다음과 같은 일을하고 싶다 :
Model Limit_Choices_to = { '사용자': user}
약간의 차이점이 있습니다.
일부 모델은 다음을 설명 할 수 있습니다.
class Job(models.Model):
name = models.CharField(max_length=200)
operators = models.ManyToManyField(User)
class Activity(models.Model):
job = models.ForeignKey(Job)
job_operators = models.ManyToManyField(User, limit_choices_to={user: Job.operators} blank=True, null=True)
참고 : 구문은 반드시 정확한 것이 아니라 예시적인 것입니다.
이제 SO SO에 대한 답변에 따라 미들웨어를 사용하여 현재 사용자를 확보하는 데 약간의 성공을 거두었습니다. , 나는 현재 작업을 식별 할 수 있으며, 따라서 운영자로서 사용자의 하위 집합을 이동할 수 있습니다.
다시 말해, 부모 분야의 많은 사람들이 선택한 것을 기반으로, 해당 하위 선택을 어린이 분야에 제공하거나 John, Jim, Jordan 및 Jesse가 작업을 수행 한 경우 해당 이름 만 선택하여 작업을 설명 할 수 있습니다. 그 직무에 대한 내부 및 활동.
BTW, 여기 미들웨어에서의 순진한 시도가 있습니다.
# threadlocals middleware
try:
from threading import local
except ImportError:
from django.utils._threading_local import local
_thread_locals = local()
def get_current_user():
return getattr(_thread_locals, 'user', None)
def get_current_job():
return getattr(_thread_locals, 'job', None)
class ThreadLocals(object):
"""Middleware that gets various objects from the
request object and saves them in thread local storage."""
def process_request(self, request):
_thread_locals.user = getattr(request, 'user', None)
_thread_locals.job = getattr(request.POST["job"], 'job', None)
그리고 활동 모델 :
operators = modes.ManyToManyField(User, limit_choices_to=dict(Q(User.objects.filter(job==threadlocals.get_current_job)))
고맙습니다.
해결책
좋아, 나는 당신의 작품에 Monkey Wrench를 던지는 것을 싫어하지만 ThreadLocals 해킹을 진지하게 사용할 필요는 없습니다.
사용자는 요청 객체에 있으므로 미들웨어를 사용하여 추출 할 필요가 없습니다. 그것은 모든 관점에 대한 논쟁으로 전달됩니다.
양식 선택을 제한하는 요령은 모델에서 한계 선택을 수행하는 대신 양식에 사용 된 쿼리 세트를 동적으로 변경하는 것입니다.
그래서 당신의 양식은 다음과 같습니다.
# forms.py
from django import forms
from project.app.models import Activity
class ActivityForm(forms.ModelForm):
class Meta:
model Activity
그리고 당신의 견해는 다음과 같습니다.
# views.py
...
form = ActivityForm(instance=foo)
form.fields['job_operators'].queryset = \
User.objects.filter(operators__set=bar)
...
이것은 단지 빠른 스케치이지만 일반적인 아이디어를 제공해야합니다.
관리자의 ThreadLocals를 피하는 방법이 궁금하다면 읽으십시오. 사용자와 관리자 제임스 베넷.
편집하다: 장고에서 유용한 형태의 트릭 Collin Grady는 또한 __init__ 메소드 양식으로 쿼리 세트를 동적으로 설정하는 예를 보여줍니다.이 예는 위의 예보다 깨끗합니다.
다른 팁
그러나 list_filter로 정의하는 필드는 어떻습니까? 그들은 Limit_choices_to 만 존중합니다. 따라서 django 관리자 필터의 선택을 제한하려면 Limit_choices_to와 일부 미들웨어를 사용하여 현재 사용자를 기반으로 필터링해야합니다. 아니면 더 쉬운 솔루션이 있습니까?
원숭이 렌치를 환영합니다.
나는 또한 다른 방법을 찾았지만 덜 직접적인 것 같습니다.
class ActivityForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ActivityForm, self).__init__(*args, **kwargs)
if self.initial['job_record']:
jr = JobRecord.objects.get(pk=self.initial['job_record'])
self.fields['operators'].queryset = jr.operators
class Meta:
model = Activity
exclude = ('duration',)
나는 당신의 길이 더 좋다고 생각합니다! 감사합니다 힙!