3

我想做这样的事情:

模型 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 上的一些答案所描述的那样,但是,我希望我可以通过 request.POST 获得当前的作业,这样,如果保存了活动,我将能够识别当前的作业,因此作为操作员的用户子集将成为活动模型中可供选择的用户集。

换句话说,基于父字段中的 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)))

谢谢你。

4

3 回答 3

2

好的,我讨厌在你的作品中使用活动扳手,但你真的不需要使用 threadlocals hack。

用户在请求对象中,这意味着不需要使用中间件来提取它。它作为参数传递给每个视图。

因此,限制表单选择的技巧是动态更改表单中使用的查询集,而不是在模型中进行限制选择。

所以你的表格看起来像这样:

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

这只是一个速写,但应该给你一个大致的想法。

如果您想知道如何在管理员中避免线程本地化,请阅读James Bennett的用户和管理员

编辑: Collin Grady 在 Django 中的有用表单技巧还展示了一个以 __init__ 方法动态设置查询集的示例,这比我上面的示例更清晰。

于 2009-02-26T00:58:54.170 回答
2

但是您使用 list_filter 定义的字段呢?他们只尊重limit_choices_to。因此,如果您想限制 Django 管理过滤器的选择,您必须使用 limit_choices_to 和一些中间件来根据当前用户过滤它们。还是有更简单的解决方案?

于 2011-03-25T22:18:31.743 回答
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',)  

我觉得你的方法更好!多谢!

于 2009-02-26T01:31:53.420 回答