在Serializer上是否有一种方法可以执行创建以保存作为外键的字段

时间:2019-10-28 06:44:50

标签: django django-rest-framework

在用例上,我现在有两个模型时间表雇员,我想使用<来自动保存时间表的员工字段。 strong> perform_create ,但api返回错误“ / api / timesheet_entry / \ n的ValueError” \\ ,,]> \“:\” Timesheet.employee \“必须是\” Employee \”实例。

我想做的是使用 id 将时间表的员工字段保存到员工的登录字段中。

以下是有关模型,序列化器和视图集的信息。

class Timesheet(models.Model):
    start_date = models.DateTimeField(verbose_name="Start Date", null=True, blank=True, default=None, editable=True, help_text="", unique=False, db_index=False,)
    end_date = models.DateTimeField(verbose_name="End Date", null=True, blank=True, default=None, editable=True, help_text="", unique=False, db_index=False,)
    employee = models.ForeignKey('Employee', on_delete=models.PROTECT, related_name="timesheet_entry_employee",
        verbose_name="Employee", null=True, blank=True, editable=True, unique=False)
    comment = models.CharField(verbose_name="Comment", null=True, blank=True, default=None, editable=True, max_length=255,)
    total_hours = models.DecimalField(verbose_name="Total Hours", null=True, blank=True, default=0.00, max_digits=19, decimal_places=2,)

class Employee(models.Model):
    name = models.CharField(verbose_name="Name", max_length=255,)
    login = models.ForeignKey(User, on_delete=models.PROTECT, related_name="employee_login",
        verbose_name="Login", editable=True)
    hourly_cost = models.DecimalField(verbose_name="Hourly Cost", null=False, blank=False, editable=True, max_digits=19, decimal_places=2,)
    charge_out_rate = models.DecimalField(verbose_name="Charge Out Rate", null=False, blank=False, max_digits=19, decimal_places=2,)

和序列化器

class TimesheetEntrySerializer(WritableNestedModelSerializer):
    employee = PrimaryKeyRelatedField(many=False, read_only=False, allow_null=True, queryset=models.Employee.objects.all())

viewset的执行创建

def perform_create(self, serializer):
        user_id = self.request.user
        employee_user = models.Employee.objects.get(employee__login=user_id)
        return serializer.save(employee=employee_user)

1 个答案:

答案 0 :(得分:1)

Employee.objects.filter(...)返回一个QuerySet,它是Employees的列表。因为您的查询足够具体,所以列表将只包含一个元素but it will still be a list.

此外,您应该只使用login__id,因为您已经在查询员工。检索单个对象的正确方法是改用Employee.objects.get(login__id = request)

请注意,当.get()无法找到对象时,它将引发DoesNotExist异常。


检索当前员工的另一种方法是通过用户对象在员工上使用related_name

employee = self.request.user.employee_login

关于您的代码,我注意到了一些无关的东西:

  • 您使用login来引用用户,并使用相关名称"employee_login"来引用员工。最好仅将它们称为user'employee'
  • 您得到self.request.user.id并将其存储在名为request的变量中。虽然这本身并不会引起问题,但最好选择一个更唯一的冗长名称,例如user_id
  • 您使用self.request.user.id获取用户ID,然后使用login__id查询员工。您也可以简单地使用self.request.user检索用户,然后使用login = user查询该用户。

编辑:

我看到您正在使用

employee_user = models.TimesheetEntry.objects.get(employee__login=user_id)

这没有意义,您想要检索当前用户的雇员对象,就在这里,您正在尝试获取TimesheetEntry。

user_id = self.request.user
employee_user = models.Employee.objects.get(login=user_id)

现在,我不确定是否可以将对象实例简单地传递给PrimaryKeyRelatedField,所以可以使用

return serializer.save(employee=employee_user)

return serializer.save(employee=employee_user.id)

编辑2:

您可以通过执行以下操作完全绕过串行器:

def perform_create(self, serializer):
        user_id = self.request.user
        employee_user = models.Employee.objects.get(employee__login=user_id)
        timesheet_entry = serializer.save()
        timesheet_entry.employee = employee_user
        timesheet_entry.save()
        return timesheet_entry