我回来了更多关于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()
行上设置断点,我可以看到profile
和user
对象是我认为它们应该是的。我尝试删除用户对象,并获得上面列出的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作为数据库后端并执行初始项目makemigrations
和migrate
创建了标准的Django和django-allauth
表。这些基表中有一些与FOREIGN KEY
表有user
个关系。我对数据库的最后一次调查不是非常严格,因为昨晚真的很晚......但那些引用user
表的人没有on delete cascade
条款。所以,即使我修理了#34;我的" table(s)引用user
的基本Django表似乎是"破坏"没有cascade
条款。
如果我能确定将其发送到哪里,我会提交错误报告。
答案 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)
我可能不必实际删除配置文件实例,但我仍在测试。