ограничить выбор посторонними ключами, используя промежуточное ПО - PullRequest
3 голосов
/ 26 февраля 2009

Я хочу сделать что-то вроде этого:

Модель limit_choices_to = {'пользователь': пользователь}

с некоторыми отличиями.

Некоторые модели могут объяснить:

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, однако я надеялся, что смогу получить текущее задание через request.POST, так что если Активность была сохранена, и я смог бы распознать текущее задание, и, следовательно, подмножество пользователей как операторов, которые, в свою очередь, будут выбраны пользователем в модели действий.

Другими словами, основываясь на выборе ManyToManyField в родительском поле, предложите этот суб-выбор дочернему полю или, если Джон, Джим, Джордан и Джесси работали над заданием, выберите из этих имен только опишите работу над Деятельностью в рамках этой работы и отнесите ее к ней.

Кстати, вот моя наивная попытка в промежуточном программном обеспечении:

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

и модель Activity:

operators = modes.ManyToManyField(User, limit_choices_to=dict(Q(User.objects.filter(job==threadlocals.get_current_job)))

Спасибо.

Ответы [ 3 ]

2 голосов
/ 26 марта 2011

Но как насчет полей, которые вы определяете с помощью list_filter? Они уважают только limit_choices_to. Поэтому, если вы хотите ограничить выбор фильтров администратора Django, вы должны использовать limit_choices_to и некоторое Middleware для их фильтрации на основе текущего пользователя. Или есть более простое решение?

2 голосов
/ 26 февраля 2009

Хорошо, я не хочу бросать гаечный ключ в твои работы, но тебе серьезно не нужно использовать хаки для локальных потоков.

Пользователь находится в объекте запроса, что означает, что нет необходимости извлекать его с помощью промежуточного программного обеспечения. Он передается в качестве аргумента каждому представлению.

Следовательно, хитрость в ограничении выбора формы заключается в динамическом изменении набора запросов, используемого в форме, а не в ограничении выбора в модели.

Итак, ваша форма выглядит так:

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

Это всего лишь быстрый набросок, но он должен дать вам общее представление.

Если вам интересно, как избежать локальных потоков в админе, прочитайте Пользователи и админы от Джеймса Беннетта.

Редактировать: Полезные приемы работы с формами в Django от Collin Grady также показывает пример динамической установки набора запросов в методе формы __init__, который чище, чем в моем примере выше.

0 голосов
/ 26 февраля 2009

Ключи от Обезьяны Добро пожаловать, друг!

Я также нашел другой способ, хотя он кажется менее прямым:

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

Я думаю, что ваши пути лучше! Спасибо, куча!

...