gpt4 book ai didi

python - 如何防止从 Django Admin 中删除 Django 模型,除非是级联的一部分

转载 作者:行者123 更新时间:2023-12-03 22:05:04 25 4
gpt4 key购买 nike

我有一个使用 Django 2.2.4 的项目。

我有一个名为 Company 的 Django 模型。

我使用 post_save 信号来确保一旦创建了新公司,就会创建一个名为“Billing”的新模型实例,该实例与该公司相关联。这包含公司的帐单信息。这很好用。

由于我的 Billing 对象与公司关联,并且我使用 on_delete=models.CASCADE ,因此一旦删除公司,与该公司关联的 Billing 对象也会自动删除。这也很好用。

由于每个公司的 Billing 对象现在与 Company 一起自动创建和删除,因此使用 Django Admin Web 界面的管理员无需手动创建或删除 Billing 对象。我想对他们隐藏这个功能。

通常,防止 Django Admin 允许某人添加或删除对象的常用方法是将其添加到 admin.py 中该模型的 ModelAdmin:

class BillingAdmin(admin.ModelAdmin):
...

# Prevent deletion from admin portal
def has_delete_permission(self, request, obj=None):
return False

# Prevent adding from admin portal
def has_add_permission(self, request, obj=None):
return False

这有效,并且确实隐藏了管理员手动创建或删除 Billing 对象实例的能力。然而,它确实有一个负面影响:Django Admin 用户不能再删除公司。删除公司时,Django 会查找所有需要删除的关联对象,注意到不允许用户删除关联的 Billing 对象,并阻止用户删除公司。

虽然我不希望 Django Admin 用户能够手动创建或删除 Billing 模型的实例,但我仍然希望他们能够删除整个 Company,这将导致删除关联的 Billing 模型的实例与那家公司。

就我而言,阻止用户删除 Billing 模型的实例与其说是一项安全功能,不如说是为了防止混淆,因为它不会让数据库最终处于公司存在但没有计费对象的状态为它而存在。 Django 显然不会有这个问题,但它会混淆用户。

有解决方法吗?

更新:

设置 has_delete_permission 后,如果您尝试通过 Django Admin 删除公司,则会得到以下信息:

enter image description here

不会抛出任何异常。至少没有没有被捕获,并出现在 Django 日志中。

我的模型看起来像这样:
class Company(Group):
...

class Billing(models.Model):
company = AutoOneToOneField('Company', on_delete=models.CASCADE, blank=False, null=False, related_name="billing")
monthly_rate = models.DecimalField(max_digits=10, decimal_places=2, default=0, blank=False, null=False)

# Create billing object for a company when it is first created
@receiver(post_save, sender=Company)
def create_billing_for_company(sender, instance, created, *args, **kwargs):
if created:
Billing.objects.create(company=instance)

AutoOneToOneField 是 django-annoying 的一部分。它确保如果您运行 MyCompany.billing,并且关联的计费对象尚不存在,则会自动创建一个,而不是引发异常。此处可能不需要,因为我在创建公司时会自动创建对象,但这不会造成伤害,并确保我的代码永远不需要担心关联的对象不存在。

另请注意,我没有覆盖我的 Billing 模型的 delete 函数。

最佳答案

经过一番挖掘,does appear ModelAdmin 只会在对象上调用 delete(),这意味着它不应该专门查看您的 admin 计费权限。 Looking at the model delete 还确认它不关心管理员权限是什么。

我很好奇,想知道 has_delete_permission 函数是否会查看相关对象。 That also didn't appear to be the case 。此时,我很好奇您是否覆盖了 Billing 模型的 delete 函数?这将阻止删除,并且如果您将 CASCADE 设置为关系的 on_delete,则此时将不允许您完成删除 Company,因为它无法级联删除。

如果您有堆栈跟踪或明确的错误消息,请分享。

话虽如此,我不知道我是否同意这种方法。我认为在 Billing 的模型级别强制执行这一点会更有意义。尝试 delete 时,您可以检查 Billing 是否没有其他 Company 对象,如果是,则引发验证错误,通知用户 Company 必须至少有一个 Billing 。我不知道你的模型,因为它们没有发布,所以如果是一对一的关系,请忽略这一点。这是我希望它看起来如何的粗略想法:

def delete(self):
other_billing = Billing.objects.filter(company_id=self.company.id).exclude(id=self.id).first()
if not other_billing:
raise ValidationError({"message": "A company must have at least one Billing."})
super().delete()

编辑 :这是一个使用 ModelAdmin.delete_model() 的方法,它不会引发异常。

def delete_model(self, request, billing):
other_billing = Billing.objects.filter(company_id=billing.company.id).exclude(id=billing.id).first()
if not other_billing:
# from django.contrib import messages
messages.error(request, "A company must have at least one Billing.")
else:
super().delete_model(request, billing)

编辑: 我确实发现您可以访问 request ,这似乎是通过 has_delete_permissions() 检查您是否在模型的管理更改页面上的唯一可靠方法。为了记录 我认为这种方式是hacky,我不推荐它 。但是,它允许级联删除,而不允许通过更改页面删除(它将隐藏按钮):

def has_delete_permissions(self, request, obj=None):
# If we have an object, it's been fetched for deletion or to check permission against it.
if isinstance(obj, Billing):
if request.path == reverse("admin:<APP_NAME>_billing_change", args=[obj.id]):
return False

return True

关于python - 如何防止从 Django Admin 中删除 Django 模型,除非是级联的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57661025/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com