如何基于用户限制Django Inlineformset_工厂中的选择?

如何基于用户限制Django Inlineformset_工厂中的选择?,django,django-forms,Django,Django Forms,我有一个时间表应用程序,我想限制项目的用户可以分配他们的时间到他们的工作项目 型号我的型号是这样的 class Project (models.Model): name = models.CharField( verbose_name = 'Project Title', max_length = 80 ) code = models.CharField( verbose_name = 'Project Code',

我有一个时间表应用程序,我想限制项目的用户可以分配他们的时间到他们的工作项目

型号我的型号是这样的

class Project (models.Model):
    name = models.CharField(
        verbose_name = 'Project Title',
        max_length = 80
    )
    code = models.CharField(
        verbose_name = 'Project Code',
        max_length = 15
        )
    supervisor = models.ForeignKey (
        User,
        on_delete=models.CASCADE
    )
    staff = models.ManyToManyField (
        User,
        related_name= "project_resources"
    )

    def __str__(self):
        return u'%s' % (self.name)

    class Meta:
        ordering = ['name']

class Timesheet (models.Model):
    user = models.ForeignKey (
        User,
        on_delete=models.CASCADE)
    start_date = models.DateField (
        verbose_name = "Start Date"
    )

    def __str__(self):
        return u'%s | %s' % (self.user, self.start_date)

    class Meta:
        ordering = ['user','start_date']

class TimesheetRow (models.Model):
    ''' specifies a timesheet row which is unique based on Timesheet, Project and Labour Category
    '''
    timesheet = models.ForeignKey(
        Timesheet,
        on_delete=models.CASCADE
        )
    project = models.ForeignKey(
        Project,
        on_delete=models.CASCADE
        )
    labor = models.ForeignKey(
        LaborCategory,
        on_delete=models.CASCADE
        )

    sunday = models.DecimalField (default = 0, max_digits=4, decimal_places=2)
    monday = models.DecimalField (default = 0, max_digits=4, decimal_places=2)
    tuesday = models.DecimalField (default = 0, max_digits=4, decimal_places=2)
    wednesday = models.DecimalField (default = 0, max_digits=4, decimal_places=2)
    thursday = models.DecimalField (default = 0, max_digits=4, decimal_places=2)
    friday = models.DecimalField (default = 0, max_digits=4, decimal_places=2)
    saturday = models.DecimalField (default = 0, max_digits=4, decimal_places=2)

    def __str__(self):
        return u'%s | %s' % (self.timesheet.user, self.timesheet.start_date)

    class Meta:
        unique_together = ('timesheet', 'project', 'labor',)
        ordering = ['timesheet', 'project','labor']
我的表格如下所示

class TimesheetForm(forms.ModelForm):
    class Meta:
        model = Timesheet
        fields = ['id', 'user', 'start_date']
        widgets = {
            'user' : forms.HiddenInput(),
            'id' : forms.HiddenInput(),
            'start_date' : forms.HiddenInput(),
        }

class TimesheetRowInlineForm(forms.ModelForm):
    class Meta:
        model = TimesheetRow
        exclude =['timesheet']
        widgets = {
            'id' : forms.HiddenInput(),
            'project' : forms.Select(attrs={'class' : 'form-control'}),
            'labor' : forms.Select(attrs={'class' : 'form-control'}),
            'sunday' : forms.NumberInput(attrs={'class' : 'form-control'}),
            'monday' : forms.NumberInput(attrs={'class' : 'form-control'}),
            'tuesday' : forms.NumberInput(attrs={'class' : 'form-control'}),
            'wednesday' : forms.NumberInput(attrs={'class' : 'form-control'}),
            'thursday' : forms.NumberInput(attrs={'class' : 'form-control'}),
            'friday' : forms.NumberInput(attrs={'class' : 'form-control'}),
            'saturday' : forms.NumberInput(attrs={'class' : 'form-control'}),
        }

TimesheetRowInlineFormSet = forms.inlineformset_factory(
    Timesheet,
    TimesheetRow,
    form=TimesheetRowInlineForm,
    extra=1,
    exclude = ['id'],
    can_delete=True,
    can_order=False)
这给了我一个很好的表单,通过视图一切都很好,但我无法确定如何将TimesheetRowInlineForm上的项目下拉列表限制为
staff
中的那些用户

为完整起见,这是视图

class TimesheetView (LoginRequiredMixin, UpdateView):
    model = Timesheet
    form_class = TimesheetForm
    success_url = '/'

    def get_start_date(self, *args, **kwargs):
        try:
            start_date = self.kwargs['start_date']
        except:
            today = datetime.date.today()
            start_date = today - datetime.timedelta(7+ ((today.weekday()+1)%7) )
        return start_date

    def get_object(self, *args, **kwargs):
        obj, created = Timesheet.objects.get_or_create(user=self.request.user, start_date=self.get_start_date())
        return obj

    def get_context_data(self, **kwargs):
        data = super(TimesheetView, self).get_context_data(**kwargs)

        if self.request.POST:
            data['timesheetrows'] = TimesheetRowInlineFormSet(self.request.POST, instance=self.get_object())
        else:
            data['timesheetrows'] = TimesheetRowInlineFormSet(instance=self.get_object())
        return data

    def get_initial(self):
        return { 'user': self.request.user,
                'start_date' : self.get_start_date() }

    def form_valid(self, form):
        context = self.get_context_data()
        timesheetrows = context['timesheetrows']
        with transaction.atomic():
            self.object = form.save()

            if timesheetrows.is_valid():
                timesheetrows.instance = self.object
                timesheetrows.save()
        return super(TimesheetView, self).form_valid(form)
编辑

我已经解决了如何在admin中实现这一点,即:

class  TimesheetRowAdmin(admin.ModelAdmin):
    def get_model_perms(self, request):
        """
        Return empty perms dict thus hiding the model from admin index.
        """
        return {}
admin.site.register(TimesheetRow, TimesheetRowAdmin)

class TimesheetRowInline(admin.TabularInline):
    model = TimesheetRow
    can_delete = True
    extra = 1

    def formfield_for_foreignkey(self, db_field, request=None,**kwargs):
        field = super(TimesheetRowInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
        if db_field.name == 'project':
            if request.user is not None:
                field.queryset = field.queryset.filter(staff=request._obj_.user)
                if not field.queryset:
                    field.queryset = field.queryset.all()
            else:
                field.queryset = field.queryset.none()
        return field

class TimesheetAdmin(admin.ModelAdmin):
    list_display = ['user', 'start_date']
    ordering = ['user','start_date']
    inlines = [TimesheetRowInline]

    def get_form(self, request, obj=None, **kwargs):
        request._obj_ = obj
        return super().get_form(request, obj, **kwargs)

admin.site.register(Timesheet, TimesheetAdmin)

对于非员工用户,我仍然需要考虑这一点。

在上面的管理中解决了这个问题。在我看来,这就是我解决问题的方法。我在视图中有效地动态创建表单

class TimesheetView (LoginRequiredMixin, UpdateView):
    model = Timesheet
    form_class = TimesheetForm
    success_url = '/'

    def create_inline_form(self):
        class DynamicTimesheetRowInlineForm (forms.ModelForm):
            project = forms.ModelChoiceField(queryset=Project.objects.filter(staff=self.request.user),
                                             widget=forms.Select(attrs={'class' : 'form-control'}))
            class Meta:
                model = TimesheetRow
                exclude =['timesheet']
                widgets = {
                    'id' : forms.HiddenInput(),
                    #'project' : forms.Select(attrs={'class' : 'form-control'}),
                    'labor' : forms.Select(attrs={'class' : 'form-control'}),
                    'sunday' : forms.NumberInput(attrs={'class' : 'form-control'}),
                    'monday' : forms.NumberInput(attrs={'class' : 'form-control'}),
                    'tuesday' : forms.NumberInput(attrs={'class' : 'form-control'}),
                    'wednesday' : forms.NumberInput(attrs={'class' : 'form-control'}),
                    'thursday' : forms.NumberInput(attrs={'class' : 'form-control'}),
                    'friday' : forms.NumberInput(attrs={'class' : 'form-control'}),
                    'saturday' : forms.NumberInput(attrs={'class' : 'form-control'}),
                }
        return DynamicTimesheetRowInlineForm               

    def get_start_date(self, *args, **kwargs):
        try:
            start_date = self.kwargs['start_date']
        except:
            today = datetime.date.today()
            start_date = today - datetime.timedelta( ((today.weekday()+1)%7) )
        return start_date

    def get_object(self, *args, **kwargs):
        obj, created = Timesheet.objects.get_or_create(user=self.request.user, start_date=self.get_start_date())
        return obj

    def get_context_data(self, **kwargs):
        data = super(TimesheetView, self).get_context_data(**kwargs)

        DynamicTimesheetRowInlineFormSet = forms.inlineformset_factory(
            Timesheet,
            TimesheetRow,
            form=self.create_inline_form(),
            extra=1,
            exclude = ['id'],
            can_delete=True,
            can_order=False)

        data['timesheetrows'] = DynamicTimesheetRowInlineFormSet(self.request.POST or None,
                                                          instance=self.get_object())
        return data

    def get_initial(self):
        return {'user': self.request.user,
                'start_date' : self.get_start_date() }

    def form_valid(self, form):
        context = self.get_context_data()
        timesheetrows = context['timesheetrows']

        print (timesheetrows.errors)

        with transaction.atomic():
            self.object = form.save()

            if timesheetrows.is_valid():
                timesheetrows.instance = self.object
                timesheetrows.save()
        return super(TimesheetView, self).form_valid(form)

这是一件常见的事情-限制访问。可以使用
has\u perm
、使用
is\u staff
、使用特定查询等来完成。您尝试过什么?如果这很常见,我无法理解为什么我无法看到以前有人是如何完成的。我发现很难相信我是唯一一个对此不明显的人。我在任何地方都找不到我想要实现的任何例子。