在Django中创建项目后将项目添加到多对多 [英] Adding an item to many to many after creation in django

查看:67
本文介绍了在Django中创建项目后将项目添加到多对多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我一直在尝试与此相关的事情.将该家庭视为一个Facebook群组.

Recently I've been trying to do something with this. Think of the family as a facebook group.

class Family(models.Model):
    name = models.CharField(max_length=50)
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owned_families')
    users = models.ManyToManyField(User, related_name='families', blank=True)

为了说明起见,假设我们有一个称为 fm 的族对象.

我的问题是,所有者 users 之一,对吗?我的意思是,当有人创建家庭时,他现在是所有者吗?他拥有它,但仍然是它的用户列表中列出的用户.现在,当我创建一个新的家族 fm 时,我想将 fm.owner 添加到 fm.users .

let's assume we have this family object called fm, for illustration purpose.

My problem is, The owner is one of the users right? I mean, When someone creates a family, He's now the owner right? he owns it but he's still a user listed in it's users list. Now, when I create a new family fm , I want to add the fm.owner to fm.users.

让我们谈谈我尝试过的事情.

Let's talk about what I've tried.

  • post_save 信号不适用于m2m. X

  • post_save signal doesn't work with m2m. X

m2m_changed 在更改字段而不创建时发生. X

m2m_changed happens when the field is changed, not created. X

    def save(self, *args, **kwargs):
        old = self.pk
        super(Family, self).save(*args, **kwargs)

        if old is None:
            print('This actually shows up')
            self.users.add(self.owner)

基本上,这每次都会保存pk,第一次创建家庭时,在调用 super ..... 之前,它没有 .pk ,所以我依靠它来检查它是否没有pk(创建时).

Basically, this saves the pk each time, First time a family is created, Before calling super..... it has no .pk so I'm counting on this to check if it had no pk (On creation).

问题是 self.users.add(self.owner)无法正常工作.

我试图克隆整个对象,并像这样跟踪它

I've tried to clone the object as whole and keep track of it like

    def save(self, *args, **kwargs):
        old = self
        super(Family, self).save(*args, **kwargs)

        if old is None:
            print("This actually doesn't show up")
            self.users.add(self.owner)

这实际上是可怕的,它需要对自身进行引用,并在调用 super .... self 及其引用 old 发生了变异,我只想向大家展示一下,因为这个问题本身可以解决某人的问题.

This actually is terrible, It takes a refernce to self and when calling super...., The selfand it's reference old gets mutated, I just wanted to show this as this question itself might solve someone's problem.

所以我解决了这个问题.

So I solved this by.

import copy
    def save(self, *args, **kwargs):
        old = copy.deepcopy(self)
        super(Family, self).save(*args, **kwargs)

        if old is None:
            print('This actually shows up')
            self.users.add(self.owner)

但是 self.users.add(self.owner)仍然不起作用.

我想念什么?

推荐答案

问题可能是在django管理员中,实例被首先保存,而在之后被保存,内联表单集和m2m-字段被保存.如果所有者不在其中,它将被删除.您可以在管理员中覆盖某些功能来解决此问题:

The problem is probably that in the django admin, the instance is saved first, and only after that the inline formsets and m2m-fields are saved. If the owner is not in there, it will be removed. You can override some functionality in the admin to remedy this:

class FamilyAdmin(ModelAdmin):
    def save_related(self, request, form, formsets, change):
        super(FamilyAdmin, self).save_related(request, form, formsets, change)
        form.instance.users.add(form.instance.owner)

此外,您可以尝试(请注意,还有其他方法可以删除没有被任何信号或其他钩子拾取的所有者),以防止代码删除所有者:

Furthermore, you can try (note that there are other ways to remove the owner that are not picked up by any signal or other hook) to prevent code from removing the owner:

from django.db.models.signals import m2m_changed
from django.dispatch import receiver

@receiver(m2m_changed, sender=Family.users.through)
def famliy_users_changed(sender, **kwargs):
    family = kwargs['instance']
    pk_set = kwargs['pk_set']
    action = kwargs['action']
    if action == "pre_add":
        pk_set.add(family.owner_id)
    if action == "pre_remove":
        pk_set.remove(family.owner_id)
    if action == "post_clear":
        family.users.add(family.owner)

但是通常来说,您正在跳过这些麻烦,因为您正在使数据不规范化(将所有者归入用户会使该信息变得多余,从而迫使您保持数据正确).由于您始终知道所有者是用户之一,所以为什么不将其包装在方法中

But generally speaking, you are jumping through those hoops because you are denormalizing your data (putting the owner in users makes that information redundant, forcing you to keep your data correct). Since you always know the owner is one of the users, why not wrap that in a method

class Family(...):
    # ...
    def members(self):
        return User.objects.filter(Q(pk__in=self.users.all()|Q(pk=self.owner_id)))

并通过这种方法访问家庭成员?

and access family members through that method?

这篇关于在Django中创建项目后将项目添加到多对多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆