Oct*_*one 3 django postgresql django-models
我有一个 Django 模型,其外键关系标记为deletion.PROTECT,我对此行为感到满意,因为这是模型在大多数情况下的行为方式。
然而,这些模型有一个用例,我需要执行“硬删除”(即用户想要删除他们的帐户)。在这种情况下,我真的希望一切都表现得像 a CASCADE,而不必手动删除每个外键关系。有没有办法干净地做到这一点?在理想情况下, model.delete() 调用将采用类似于 的参数force_cascade=True。
由于 django 还创建具有受保护关系的数据库,因此您需要自己手动执行级联删除。否则数据库本身将禁止删除。
Django 的 ORM 可以帮助你,你唯一需要做的就是递归地查找所有对用户的引用并以相反的顺序删除它们。手动执行此操作也是一个优点,因为您可能希望用替代者(即虚拟“已删除用户”)替换某些出现的用户。我可以想到留言板中的评论,即使用户删除了他们的帐户,也应该保留这些评论。
要查找指向当前用户的关系并将其替换为幽灵用户,您可以使用以下代码片段。
from typing import List
from django.contrib.auth import get_user_model
from django.db.models import Model
from django.db.models.fields.reverse_related import (
ManyToOneRel,
ForeignObjectRel,
)
User = get_user_model()
def get_all_relations(model: Model) -> List[ForeignObjectRel]:
"""
Return all Many to One Relation to point to the given model
"""
result: List[ForeignObjectRel] = []
for field in model._meta.get_fields(include_hidden=True):
if isinstance(field, ManyToOneRel):
result.append(field)
return result
def print_updated(name, number):
"""
Simple Debug function
"""
if number > 0:
print(f" Update {number} {name}")
def delete_user_and_replace_with_substitute(user_to_delete: User):
"""
Replace all relations to user with fake replacement user
:param user_to_delete: the user to delete
"""
replacement_user: User = User.objects.get(pk=0) # define your replacement user
# replacement_user: User = User.objects.get(email='email@a.com')
for field in get_all_relations(user_to_delete):
field: ManyToOneRel
target_model: Model = field.related_model
target_field: str = field.remote_field.name
updated: int = target_model.objects.filter(
**{target_field: user_to_delete}
).update(**{target_field: replacement_user})
print_updated(target_model._meta.verbose_name, updated)
user_to_delete.delete()
Run Code Online (Sandbox Code Playgroud)
对于真正的删除,只需用调用替换该.update(...)函数.delete()(如果需要,不要忘记之前递归地查找受保护的关系)
可能还有一个我不知道的与 postgresql 相关的解决方案。给定的解决方案是独立于数据库的。
一般来说,最好保持每个关系受保护,以防止意外删除重要的数据库条目并小心手动删除。
| 归档时间: |
|
| 查看次数: |
5227 次 |
| 最近记录: |