Непонятные ошибки при попытке сохранить данные при переопределении метода create по умолчанию - PullRequest
0 голосов
/ 03 февраля 2020

Пытался написать собственный метод create для моей модели, но столкнулся с некоторыми неясными ошибками.

Вот мой код:

# models.py:
class ItemModel(models.Model):
   item_id = models.CharField(max_length=10, primary_key=True)
   name = models.CharField(max_length=40)
   active = models.BooleanField(default=True)

   def __str__(self):
       return self.item_id


class ItemVersion(models.Model):
   item_ver_id = models.CharField(max_length=13, primary_key=True)
   item_ver = models.TextField()
   config = models.TextField()
   model = models.ForeignKey(ItemModel, on_delete=models.CASCADE, default=0)
   session_id = models.CharField(max_length=40, default=0)
   creation_date = models.DateTimeField(auto_now=False, auto_now_add=True)
   finished = models.BooleanField(default=False)

   def name(self):
      return self.model.name

   def __str__(self):
       return str(self.model)
# serializers.py:
class ItemModelSerializer(serializers.ModelSerializer):
   item_id = serializers.RegexField(regex='^\d{3}-\d{9}$', allow_blank=False)
   name = serializers.CharField(min_length=6, max_length=50, allow_blank=False)

   class Meta:
      model = ItemModel
      fields = '__all__'


class ItemVersionSerializer(serializers.ModelSerializer):
   item_ver_id = serializers.RegexField(regex='^r\d{2}$', allow_blank=False)
   session_id = serializers.RegexField(regex='^s\d{2}$', allow_blank=False)
   link = serializers.SerializerMethodField()
   name = serializers.SerializerMethodField()
   config = serializers.CharField(min_length=6)
   item_ver = serializers.CharField(min_length=6)

   def get_name(self, obj):
      return obj.name()

   def get_link(self, obj):
      link = 'https://example.net/' + str(obj.model)
        + str('-dyn') + '/?iv_id=' + str(obj.item_ver_id)
        + '&sessid=' + str(obj.session_id)
      return link
# views.py:
class ItemModelViewSet(viewsets.ModelViewSet):
   queryset = ItemModel.objects.all()
   serializer_class = ItemModelSerializer
   lookup_field = 'item_id'


class ItemVersionViewSet(viewsets.ModelViewSet):
   serializer_class = ItemVersionSerializer
   lookup_field = 'item_ver_id'

   def get_queryset(self):
       pass

   def create(self, request, *args, **kwargs):
       data = request.data
       model = ItemModel.objects.get(item_id=data["model"])
       item_version = ItemVersion.objects.create(
          # model=model,
          item_ver_id=data["item_ver_id"],
          config=data["config"],
          item_ver=data["item_ver"],
          session_id=data["session_id"]
          # finished=data["finished"]
       )
       item_version.model.add(model)
       finished = True if data["finished"] else False
       item_version.finished.add(finished)
       item_version.save()

       serializer = ItemVersionSerializer(item_version)
       return Response(data)

Для некоторых причина, я продолжаю получать FOREIGN KEY constraint failed и строка session_id=data["session_id"] выделяется как та, где проблема возникает поблизости.

Есть идеи, как решить эту проблему?

Редактировать: traceback:

Traceback (most recent call last):
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 383, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: FOREIGN KEY constraint failed

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/rest_framework/viewsets.py", line 116, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/rest_framework/views.py", line 495, in dispatch
    response = self.handle_exception(exc)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/rest_framework/views.py", line 455, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/rest_framework/views.py", line 492, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/aqv/workspace/django_rest_fw/ct_test/core/views.py", line 47, in create
    session_id=data["session_id"]
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/query.py", line 422, in create
    obj.save(force_insert=True, using=self.db)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/base.py", line 779, in save_base
    force_update, using, update_fields,
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/base.py", line 870, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/base.py", line 908, in _do_insert
    using=using, raw=raw)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/query.py", line 1186, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1332, in execute_sql
    cursor.execute(sql, params)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/utils.py", line 99, in execute
    return super().execute(sql, params)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/home/aqv/workspace/django_rest_fw/ct_test/environ/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 383, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: FOREIGN KEY constraint failed

1 Ответ

2 голосов
/ 04 февраля 2020

Единственный внешний ключ, который я вижу, это model, и в вашем коде вы его не передаете.

def create():
   model = ItemModel.objects.get(item_id=data["model"])
   item_version = ItemVersion.objects.create(
      # model=model,
      ...

Это вызовет проблему ограничения FK, если вы не передадите действительный экземпляр модели или идентификатор, потому что:

  1. У вас есть default=0 для поля модели
  2. Но * ItemModel с pk = 0 в данных не существует

Если вы хотите, чтобы model обнулялся, то вы можете просто добавить это к определение FK:

class ItemVersion(models.Model):
   ...
   model = models.ForeignKey(ItemModel, null=True, on_delete=CASCADE)

Позже я вижу, что у вас есть эти 2 строки:

  • item_version.model.add()
  • item_version.finished.add(finished).

Они оба неверны. add() не работает с полем логической модели, а .add() для FK действителен только для многих-многих FK, которые здесь не используются. Способ их передачи в закомментированных разделах - это хорошо.

Вы можете получить значение по умолчанию для флага «готово», сказав:

data.get('finished', False)

# this will throw a KeyError if "finished" isn't in the dict
True if data["finished"] else False

# this will not throw an error (but doesn't check the value of finished)
True if "finished" in data else False

Некоторые другие примечания:

1) Вы используете ModelSerializer без мета-класса внутри. Подумайте только об использовании стандартного сериализатора, если вы действительно хотите сделать это вручную, или читайте на ModelSerializer. Если вы используете его правильно, вам не нужен специальный метод создания в наборе.

2) default=<anything> не очень хорошая идея для FK. Обычно FK не должен иметь значение по умолчанию (хотя в некоторых случаях это приятно, например, с заранее определенными системными данными в константных таблицах)

3) В вашем create не используется сериализатор метод. Вы обращаетесь к request.data напрямую. Это не даст вам подтверждения и не сможет сказать finished=BooleanField(default=False) и всегда получить значение для serializer.validated_data['finished'].

...