DeleteView CBV中的IntegrityError异常

时间:2018-03-19 11:26:20

标签: django python-3.x sqlite

我回来了更多关于Django Class Based View的问题。我有一个"扩展" {&1;}"形式的user模型"模型。配置文件模型使用CBV来实现CRUD功能,但DeleteView始终生成FOREIGN KEY constraint failed IntegrityError异常。我知道这意味着什么,但我不知道为什么我会得到那个例外。

我有内置的Django user模型和一个"帐户适配器"和我的自定义Profile模型。帐户适配器只是将注册电子邮件地址设置为用户名:

class AccountAdapter(DefaultAccountAdapter):
    def save_user(self, request, user, form, commit=True):
        Log.add("")
        data = form.cleaned_data
        user.username = data['email']  # username not in use
        user.email = data['email']
        if 'password1' in data:
            user.set_password(data['password1'])
        else:
            user.set_unusable_password()

        self.populate_username(request, user)

        if commit:
            user.save()

        return user

Profile模型有OneToOneField将个人资料实例附加到用户。

class Profile(models.Model):
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        blank=False,
        null=False,
    )

DeleteView CBV是:

@method_decorator(verified_email_required, name='dispatch')
class Delete(DeleteView):
    pk_url_kwarg = "account_number"
    model = Profile
    form_class = ProfileForm
    success_url = "/accounts/logout.html"

    def get(self, request, *args, **kwargs):
        try:
            profile = self.model.objects.get(account_number=self.kwargs[self.pk_url_kwarg])

            user = User.objects.get(pk=profile.user.pk)
            user.delete()

            messages.success(request, "The user is deleted")
            my_render = render(request, self.success_url)
        except User.DoesNotExist:
            messages.error(request, "User does not exist")
            my_render = render(request, self.success_url)
        except IntegrityError:
            messages.error(request, "DB IntegrityError")
            my_render = render(request, self.success_url)

        return my_render

Delete.get方法中,我可以在user.delete()行上设置断点,我可以看到profileuser对象是我认为它们应该是的。我尝试删除用户对象,并获得上面列出的IntegrityError异常。

堆栈跟踪看起来像:

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/Members/Profile/d83622e4-4816-42a4-8419-2fd389c7e3fd/delete?csrfmiddlewaretoken=y3W0ze1SfN50Mx3eymEZQQPd21u5wjf0tHvRZM0PggLX12mdAgdEGUkw3lw2KnKn

Django Version: 2.0.3
Python Version: 3.6.3
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django_extensions',
 'django.contrib.sites',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'auditlog',
 'widget_tweaks',
 'Members.apps.MembersConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'auditlog.middleware.AuditlogMiddleware']



Traceback:

File "C:\Program Files\Python36\lib\site-packages\django\db\backends\base\base.py" in _commit
  239.                 return self.connection.commit()

The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:

File "C:\Program Files\Python36\lib\site-packages\django\core\handlers\exception.py" in inner
  35.             response = get_response(request)

File "C:\Program Files\Python36\lib\site-packages\django\core\handlers\base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "C:\Program Files\Python36\lib\site-packages\django\core\handlers\base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Program Files\Python36\lib\site-packages\django\views\generic\base.py" in view
  69.             return self.dispatch(request, *args, **kwargs)

File "C:\Program Files\Python36\lib\site-packages\django\utils\decorators.py" in _wrapper
  62.             return bound_func(*args, **kwargs)

File "C:\Program Files\Python36\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view
  21.                 return view_func(request, *args, **kwargs)

File "C:\Program Files\Python36\lib\site-packages\allauth\account\decorators.py" in _wrapped_view
  32.             return view_func(request, *args, **kwargs)

File "C:\Program Files\Python36\lib\site-packages\django\utils\decorators.py" in bound_func
  58.                 return func.__get__(self, type(self))(*args2, **kwargs2)

File "C:\Program Files\Python36\lib\site-packages\django\views\generic\base.py" in dispatch
  89.         return handler(request, *args, **kwargs)

File "C:/Users/Me/PycharmProjects/MyProject/MyApp\Members\views\profile.py" in get
  103.             user.delete()

File "C:\Program Files\Python36\lib\site-packages\django\db\models\base.py" in delete
  891.         return collector.delete()

File "C:\Program Files\Python36\lib\site-packages\django\db\models\deletion.py" in delete
  307.                             sender=model, instance=obj, using=self.using

File "C:\Program Files\Python36\lib\site-packages\django\db\transaction.py" in __exit__
  212.                         connection.commit()

File "C:\Program Files\Python36\lib\site-packages\django\db\backends\base\base.py" in commit
  261.         self._commit()

File "C:\Program Files\Python36\lib\site-packages\django\db\backends\base\base.py" in _commit
  239.                 return self.connection.commit()

File "C:\Program Files\Python36\lib\site-packages\django\db\utils.py" in __exit__
  89.                 raise dj_exc_value.with_traceback(traceback) from exc_value

File "C:\Program Files\Python36\lib\site-packages\django\db\backends\base\base.py" in _commit
  239.                 return self.connection.commit()

Exception Type: IntegrityError at /Members/Profile/d83622e4-4819-42d4-8419-2fd389c7e3fd/delete
Exception Value: FOREIGN KEY constraint failed

我做错了什么?

修改

我认为我的问题出在sqlite3上。我的DB后端是sqlite3。我刚刚发现创建Profile模型表的Django迁移会创建从配置文件到User模型的外键引用,但不会创建on delete cascade子句。 Django创建的约束看起来像:

FOREIGN KEY(`user_id`) REFERENCES `auth_user`(`id`) DEFERRABLE INITIALLY DEFERRED,

我手动添加了on delete cascade选项:

FOREIGN KEY(`user_id`) REFERENCES `auth_user`(`id`) on delete cascade DEFERRABLE INITIALLY DEFERRED,

但删除操作如上所述失败。我删除了DEFERRABLE INITIALLY DEFERRED条款并仍然违规。

我有一个sqlite gui" management"工具,只是尝试使用该管理工具删除user记录并获取外键违规,因此这必须在sqlite方面。

修改2

经过更多调查后,我看到以下内容:我是python和Django的新手。我的Django测试应用程序非常小,我没有做任何/很多自定义操作。使用sqlite作为数据库后端并执行初始项目makemigrationsmigrate创建了标准的Django和django-allauth表。这些基表中有一些与FOREIGN KEY表有user个关系。我对数据库的最后一次调查不是非常严格,因为昨晚真的很晚......但那些引用user表的人没有on delete cascade条款。所以,即使我修理了#34;我的" table(s)引用user的基本Django表似乎是"破坏"没有cascade条款。

如果我能确定将其发送到哪里,我会提交错误报告。

1 个答案:

答案 0 :(得分:0)

好吧,我学到了一些东西。 Django目前不支持on delete cascade DB子句。看起来你必须自己实现这个行为。我在电子邮件“Django Users”小组中看过有关为此使用信号的帖子。

我决定在DeleteView.get()方法中尝试。

class Delete(DeleteView):
    pk_url_kwarg = "account_number"
    model = Profile
    # form_class = ProfileForm
    success_url = "account/login.html"

    def get(self, request, *args, **kwargs):
        try:
            profile = get_object_or_404(Profile, account_number=self.kwargs[self.pk_url_kwarg])
            user_pk = profile.user.pk
            profile.delete()

            get_object_or_404(User, pk=user_pk).delete()

            messages.success(request, "The user is deleted")
        except User.DoesNotExist:
            messages.error(request, "User does not exist")
        # except IntegrityError:
        #     messages.error(request, "DB IntegrityError")

        return render(request, self.success_url)

我可能不必实际删除配置文件实例,但我仍在测试。