访问模型字段内的模型实例

2024-10-02 00:29:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个模型(事件),它具有用户模型(事件所有者)的ForeignKey。 此用户可以使用以下ManyToManyField邀请其他用户:

    invites = models.ManyToManyField(
                  User, related_name="invited_users", 
                  verbose_name=_("Invited Users"), blank=True
              )

此invite字段生成一个简单的表,其中包含ID、事件ID和用户ID

如果事件所有者删除其配置文件,我不希望删除事件,而是将所有权传递给第一个被邀请的用户

所以我提出了这个函数:

    def get_new_owner():
        try:
            invited_users = Event.objects.get(id=id).invites.order_by("-id").filter(is_active=True)
            if invited_users.exists():
                return invited_users.first()
            else:
                Event.objects.get(id=id).delete()
        except ObjectDoesNotExist:
            pass

这将查找事件实例,并返回按Invite表ID排序的活动受邀请用户,因此我可以获取此查询集的第一项,它对应于第一个受邀请的用户

为了在用户被删除时运行该函数,我在_delete=models.SET上使用了:

    owner = models.ForeignKey(User, related_name='evemt_owner', verbose_name=_("Owner"), on_delete=models.SET(get_new_owner()))

然后我遇到了一些问题:

  1. 它无法访问我要传递的字段的ID
  2. 我找不到一种方法将其用作类方法或其他东西,因此我不得不将函数置于模型之上。显然,这意味着它无法再访问它下面的类,因此我尝试将事件模型作为函数的参数传递,但无法使其工作

有什么想法吗


Tags: 函数用户name模型idgetmodels事件
1条回答
网友
1楼 · 发布于 2024-10-02 00:29:04

首先,我们可以为Owner字段定义一个策略,该字段将使用已更新的对象调用函数。我们可以定义这样的删除,例如在<i.app_name/deletion.py文件中:

# app_name/deletion.py

def SET_WITH(value):
    if callable(value):
        def set_with_delete(collector, field, sub_objs, using):
            for obj in sub_objs:
                collector.add_field_update(field, value(obj), [obj])
    else:
        def set_with_delete(collector, field, sub_objs, using):
            collector.add_field_update(field, value, sub_objs)
    set_with_delete.deconstruct = lambda: ('app_name.SET_WITH', (value,), {})
    return set_with_delete

您应该将一个可调用的传递给SET,而不是调用该函数,因此您可以将其实现为:

from django.conf import settings
from django.db.models import Q
from app_name.deletion import SET_WITH

def get_new_owner(event):
    invited_users = event.invites.order_by(
        'eventinvites__id'
    ).filter(~Q(pk=event.owner_id), is_active=True).first()
    if invited_users is not None:
        return invited_users
    else:
        event.delete()


class Event(models.Model):
    # …
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        related_name='owned_events',
        verbose_name=_('Owner'),
        on_delete=models.SET_WITH(get_new_owner)
    )

因此,我们将在这里查看寻找要将对象传输到的用户的邀请。也许您需要从.inivites集合中排除get_new_owner中事件的当前.owner

作为@AbdulAzizBarkat says,我们可以更好地使用级联,而不是显式删除Event对象,因为这将避免无限递归,其中User删除触发可能触发Event删除的Event删除:目前这是不可能的,但稍后如果实现额外的逻辑,可能会在这种情况下结束。在这种情况下,我们可以使用:

from django.db.models import CASCADE

def SET_WITH(value):
    if callable(value):
        def set_with_delete(collector, field, sub_objs, using):
            for obj in sub_objs:
                val = value(obj)
                if val is None:
                    CASCADE(collector, field, [obj], using)
                else:
                    collector.add_field_update(field, val, [obj])
    else:
        def set_with_delete(collector, field, sub_objs, using):
            collector.add_field_update(field, value, sub_objs)
    set_with_delete.deconstruct = lambda: ('app_name.SET_WITH', (value,), {})
    return set_with_delete

并将get_new_owner重写为:

def get_new_owner(event):
    invited_users = event.invites.order_by(
        'eventinvites__id'
    ).filter(~Q(pk=event.owner_id), is_active=True).first()
    if invited_users is not None:
        return invited_users
    else:  # strictly speaking not necessary, but explicit over implicit
        return None

相关问题 更多 >

    热门问题