2009-02-25 2 views
3

를 사용하여 외래 키합니다 : 약간의 차이와제한 선택은 내가 이런 식으로 뭔가를 찾고 있어요 미들웨어

Model limit_choices_to={'user': 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에 대한 몇 가지 대답이 나와 있습니다. 그러나 요청을 통해 현재 Job을 얻을 수 있기를 바랍니다 .POST, if 활동이 저장되면 현재 작업을 식별 할 수 있으므로 사용자의 하위 집합이 연산자로 선택되며 사용자가 활동 모델에서 선택할 수 있습니다.

즉, 상위 필드의 ManyToManyField를 기반으로 해당 하위 선택을 하위 필드에 제공하거나 John, Jim, Jordan 및 Jesse이 작업을 수행 한 경우 해당 이름에서만 선택하십시오 해당 작업 내에서 활동에 대한 작업을 설명합니다.

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

감사합니다

BTW, 여기 내 순진 미들웨어의 시도이다.

+0

제쳐두고, 저는 이것을 하드 코딩 된 pk와 함께 사용하는 것이 내 목표를 더 잘 보여 주었다는 것을 알았습니다 ... 당연히 미들웨어를 사용하여 pk를 식별하는 것이 당연한 일입니까? limit_choices_to = Q (username__in = Job.objects.get (pk = 1) .operators.values ​​('username')) –

답변

2

좋아, 나는 당신의 작품에 원숭이 렌치를 던지는 것을 싫어하지만, 당신은 진지하게 해킹 해킹을 사용할 필요가 없다.

사용자가 요청 객체에 있기 때문에 미들웨어를 사용하여 추출 할 필요가 없습니다. 그것은 모든 관점에 인수로 전달됩니다.

따라서 폼 선택을 제한하는 트릭은 모델에서 제한 선택을하는 것과 반대로 폼에서 사용 된 쿼리 세트를 동적으로 변경하는 것입니다.

# 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를 피하는 방법을 알고 싶다면 Users and the admin James Bennett가 읽으십시오.

편집 : 콜린 레이디 의해Useful form tricks in Django 또한 동적으로 상기 나의 예보다 깨끗 양식 __init__ 방법에서의 검색어의 설정 예를 나타낸다.

+2

관리자에서 ModelAdmin의 올바른 메소드를 재정 의하여이 작업을 수행 할 수 있습니다. 그들 중 요청이 인수로 받아 들여진다. –

+0

@James Bennett ModelAdmin에서 대체 할 메소드의 예를 들려 줄 수 있습니까? 감사합니다 –

+0

@ 제임스 베넷 : 신경 쓰지 마세요. 이 발견 : http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey –

0

원숭이 렌치 환영합니다!덜 직접 보이지만

는 또한, 다른 방법을 찾을 것 :

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

나는 당신의 방법이 더 좋은 생각! 감사합니다.

+0

그러나, 지금은 새로운 양식에 대해서만 작동 ... 그리고 객체를 편집 할 때가 아니라 ... 수정해야합니다. –

2

그러나 list_filter로 정의한 입력란은 어떻게됩니까? limit_choices_to 만 존중합니다. 따라서 Django Admin 필터의 선택을 제한하려면 limit_choices_to 및 일부 미들웨어를 사용하여 현재 사용자를 기준으로 필터링해야합니다. 아니면 더 쉬운 해결책이 있습니까?