Cla*_*ash 22 django django-models
ForeignKeydjango上的s具有属性on_delete,用于指定删除引用对象时的行为.有没有办法为ManyToManyField获得类似的东西?
假设我有以下模型
class House(models.Model):
owners = models.ManyToManyField(Person)
Run Code Online (Sandbox Code Playgroud)
默认行为是级联,所以如果我删除碰巧拥有房子的人,它就会从所有者身上消失(显然,它不再拥有任何房屋).我想要的是,如果某人是所有者,则无法将其删除.那就是我想要的on_delete=models.PROTECT.这可能吗?
我知道内部ManyToManyField被翻译成另一个模型有两个ForeignKeys(在这种情况下一个到房子和一个到人),所以应该可以实现这一点.任何想法如何?我想避免将through属性设置为新模型,因为这会产生一个新表(我想保留旧表).
编辑:我已经跟踪了django创建适当的m2m模型的位置:
def create_many_to_many_intermediary_model(field, klass):
from django.db import models
# ...
# Construct and return the new class.
return type(name, (models.Model,), {
'Meta': meta,
'__module__': klass.__module__,
from_: models.ForeignKey(klass,
related_name='%s+' % name,
db_tablespace=field.db_tablespace),
to: models.ForeignKey(to_model,
related_name='%s+' % name,
db_tablespace=field.db_tablespace)
})
Run Code Online (Sandbox Code Playgroud)
相关的是
to: models.ForeignKey(to_model,
related_name='%s+' % name,
db_tablespace=field.db_tablespace)
Run Code Online (Sandbox Code Playgroud)
我希望它是
to: models.ForeignKey(to_model,
related_name='%s+' % name,
db_tablespace=field.db_tablespace,
on_delete=models.PROTECT)
Run Code Online (Sandbox Code Playgroud)
除了猴子修补整个事情并为ManyToManyField创建一个新类之外,还有什么办法吗?
我认为最明智的做法是使用一个显式的直通表.我意识到你已经说过你不愿意"因为这会产生一个新表(我想保留旧表)."
我怀疑你担心丢失了你的数据.如果您正在使用South,则可以轻松地将现有的自动中间表"转换"为显式的OR,您可以创建一个全新的,然后将现有数据迁移到新表中,然后再删除旧表.
这里解释了这两种方法:在django字段中添加"through"表并与South一起迁移?
考虑到您要对其定义进行的更改,我可能会选择创建新表,然后迁移数据.测试以确保所有数据仍然存在(并且您的更改符合您的要求),然后删除旧的中间表.
考虑到这些表每行只能容纳3个整数,即使你拥有很多房屋和业主,这也很可能是一个非常易于管理的工作.
如果我明白你想要的,这和我前段时间需要的类似。
您的问题:您需要保护另一个表中使用的记录不被意外删除。
我用这种方式解决了它(在Django 2和Django 3上测试)。
想象一下,你有:
TABLE1和TABLE 2,它们处于M2M关系下,其中TABLE1具有ManyToManyField。
我把主键设置为大写,以便您理解,您需要根据需要进行调整。
查看使用exists()方法的views.py并引发异常是至关重要的。
模型.py
class TABLE1(models.Model):
FIELD_M2M = models.ManyToManyField(
TABLE2,
blank=False,
related_name='FIELD_M2M',
)
#put here your code
Run Code Online (Sandbox Code Playgroud)
模型.py
class TABLE2(models.Model):
#Put here your code
Run Code Online (Sandbox Code Playgroud)
视图.py
# Delete
@login_required
def delete(request, pk=None):
try: # Delete register selected
if TABLE1.objects.filter(FIELD_M2M=pk).exists():
raise IntegrityError
register_to_delete = get_object_or_404(TABLE2, pk=pk)
# register_to_delete.register_to_delete.clear() // Uncomment this, if you need broken relationship M2M before delete
register_to_delete.delete()
except IntegrityError:
message = "The register couldn't be deleted!"
messages.info(request, message)
Run Code Online (Sandbox Code Playgroud)
这是一个丑陋的解决方案,但它有效。