如何根据用户限制Django Inlineformset_factory中的选择?

时间:2018-01-12 14:20:19

标签: django django-forms

我有一个时间表应用程序,我想限制项目,用户可以将时间分配给他们正在处理的项目。

模型我的模型看起来像这样

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']

我的 FORMS 看起来像这样。

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上的Projects下拉列表限制为staff中的那些用户。

为完整起见,这是 VIEW

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)

修改

我已经在管理员中找到了如何做到这一点,即:

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)

我仍然需要为非员工用户反映这一点。

1 个答案:

答案 0 :(得分:0)

在上面的Admin中解决了它。这就是我在我看来解决它的方式。我有效地在视图中动态创建表单。

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)