Есть ли способ на Serializer выполнить создание, чтобы сохранить поле, которое является внешним ключом - PullRequest
0 голосов
/ 28 октября 2019

У меня есть две модели Расписание и Сотрудник Теперь в моем случае использования Я хочу автоматически сохранить поле employee расписания с использованием execute_create, но API возвращает ошибку "ValueError at / api / timesheet_entry / \ nНе назначать \",,]> \ ": \" 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'sвыполнить создание

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 Ответ

1 голос
/ 28 октября 2019

Employee.objects.filter(...) возвращает QuerySet, который представляет собой список Employees. Поскольку ваш запрос достаточно специфичен, список будет содержать только один элемент, , но он все равно будет списком.

Кроме того, вы должны просто использовать login__id, так как вы уже запрашиваете сотрудника,Правильный способ извлечения одного объекта - использовать Employee.objects.get(login__id = request).

Обратите внимание, что когда .get() не может найти объект, возникает исключение DoesNotExist.


Другой способ получить текущего сотрудника - использовать related_name on employee из объекта user:

employee = self.request.user.employee_login

Несколько несвязанных вещей, которые я заметил в вашем коде:

  • Вы используете login для ссылки на пользователя и связанное имя "employee_login" для обратной ссылки на сотрудника. Лучше просто назвать их такими, какие они есть, user и 'employee'.
  • Вы получите self.request.user.id и сохраните его в переменной с именем request. Хотя это само по себе не вызывает проблем, возможно, было бы лучше выбрать более уникальное подробное имя, например user_id.
  • Вы получаете идентификатор пользователя с помощью self.request.user.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)

EDIT 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...