django ManyToManyField和on_delete

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创建一个新类之外,还有什么办法吗?

mko*_*nen 5

我认为最明智的做法是使用一个显式的直通表.我意识到你已经说过你不愿意"因为这会产生一个新表(我想保留旧表)."

我怀疑你担心丢失了你的数据.如果您正在使用South,则可以轻松地将现有的自动中间表"转换"为显式的OR,您可以创建一个全新的,然后将现有数据迁移到新表中,然后再删除旧表.

这里解释了这两种方法:在django字段中添加"through"表并与South一起迁移?

考虑到您要对其定义进行的更改,我可能会选择创建新表,然后迁移数据.测试以确保所有数据仍然存在(并且您的更改符合您的要求),然后删除旧的中间表.

考虑到这些表每行只能容纳3个整数,即使你拥有很多房屋和业主,这也很可能是一个非常易于管理的工作.


Car*_*deu 5

如果我明白你想要的,这和我前段时间需要的类似。

您的问题:您需要保护另一个表中使用的记录不被意外删除。

我用这种方式解决了它(在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)

这是一个丑陋的解决方案,但它有效。