模型限制选择为={'user': user}

16 投票
6 回答
13632 浏览
提问于 2025-04-11 09:26

我查阅了所有的文档,还去了IRC频道(顺便说一句,那是个很棒的社区),他们告诉我,无法创建一个模型并限制一个字段的选择,其中的“当前用户”是一个外键。

class Project(models.Model):
  name = models.CharField(max_length=100)
  employees = models.ManyToManyField(Profile, limit_choices_to={'active': '1'})

class TimeWorked(models.Model):
  project = models.ForeignKey(Project, limit_choices_to={'user': user})
  hours = models.PositiveIntegerField()

当然,这段代码是不能工作的,因为没有“用户”对象,但这就是我的想法,我想把“用户”对象传递给模型,只显示当前用户有项目的选择,我不想看到我没有参与的项目。

如果你能帮我或者给我一些建议,我会非常感谢。我不想让你帮我写整个应用,只想要一点建议,告诉我该怎么处理这个问题。我已经想了两天了,还是搞不明白 :(

更新: 解决方案在这里:http://collingrady.wordpress.com/2008/07/24/useful-form-tricks-in-django/,把 request.user 传给模型。

6 个回答

4

模型本身并不知道当前用户是谁,但你可以在表单的视图中把这个用户传递给模型对象(在表单重置时,choices会为必要的字段更新)。

如果你需要在管理后台使用这个功能,可以尝试使用 raw_id_admin 以及 django-granular-permissions(可以在这个链接找到:http://code.google.com/p/django-granular-permissions/,不过我自己在 Django 上快速尝试时没有成功,但看起来这个工具对 1.0 版本还是比较新鲜的)。

最后,如果你在管理后台非常需要一个下拉选择框,那你就需要对 django.contrib.admin 进行一些修改了。

6

把选择限制在当前用户身上,这是一种需要在请求过程中动态进行的验证,而不是在静态的模型定义中完成。

换句话说:当你创建这个模型的一个实例时,你会在一个视图中,这时你可以访问到当前用户,从而限制可选项。

接着,你只需要一个自定义的ModelForm,把请求中的用户信息传进去,具体例子可以参考这里: http://collingrady.wordpress.com/2008/07/24/useful-form-tricks-in-django/

from datetime import datetime, timedelta
from django import forms
from mysite.models import Project, TimeWorked

class TimeWorkedForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(ProjectForm, self).__init__(*args, **kwargs)
        self.fields['project'].queryset = Project.objects.filter(user=user)

    class Meta:
        model = TimeWorked

然后在你的视图中:

def time_worked(request):
    form = TimeWorkedForm(request.user, request.POST or None)
    if form.is_valid():
        obj = form.save()
        # redirect somewhere
    return render_to_response('time_worked.html', {'form': form})
-5

如果你想获取当前正在编辑这个模型的用户,可以使用线程本地变量(threadlocals)。线程本地中间件会把当前用户放到一个在整个进程中都能用的变量里。你可以使用这个中间件:

from threading import local

_thread_locals = local()
def get_current_user():
    return getattr(getattr(_thread_locals, 'user', None),'id',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)

查看文档,了解如何使用中间件类。然后在代码的任何地方,你都可以调用:

user = threadlocals.get_current_user

撰写回答