访问模型字段内的模型实例
Access model instance inside model field
我有一个模型(事件),它有一个指向用户模型(事件的所有者)的外键。
此用户可以使用以下 ManyToManyField 邀请其他用户:
invites = models.ManyToManyField(
User, related_name="invited_users",
verbose_name=_("Invited Users"), blank=True
)
此邀请字段生成一个简单的 table,包含 ID、event_id 和 user_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
这会找到事件实例,returns 活跃的受邀用户按邀请 table ID 排序,因此我可以获得此查询集的第一项,它对应于第一个受邀用户.
为了运行删除用户时的功能,我使用了on_delete=models.SET:
owner = models.ForeignKey(User, related_name='evemt_owner', verbose_name=_("Owner"), on_delete=models.SET(get_new_owner()))
然后我运行陷入了一些问题:
- 它无法访问我传递的字段的 ID
- 我找不到将它用作 class 方法之类的方法,所以我不得不将函数放在模型之上。显然这意味着它不能再访问它下面的class,所以我尝试将事件模型作为函数的参数传递,但无法使其工作。
有什么想法吗?
首先,我们可以为 Owner
字段定义一个策略,该策略将使用已更新的对象调用该函数。我们可以定义这样的删除,比如在<i.app_name/deletion.py
文件中:
# app_name/deletion.py
def <strong>SET_WITH</strong>(value):
if callable(value):
def set_with_delete(collector, field, sub_objs, using):
for <strong>obj in sub_objs</strong>:
collector.add_field_update(field, value(<strong>obj</strong>), <strong>[obj]</strong>)
else:
def set_with_delete(collector, field, sub_objs, using):
collector.add_field_update(field, value, sub_objs)
set_with_delete.deconstruct = lambda: ('<em>app_name</em>.SET_WITH', (value,), {})
return set_with_delete
您应该将 callable 传递给 SET
,而不是调用该函数,因此您将其实现为:
from django.conf import settings
from django.db.models import Q
from <i>app_name</i>.deletion import <b>SET_WITH</b>
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:
<b>event.delete()</b>
class Event(models.Model):
# …
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='owned_events',
verbose_name=_('Owner'),
on_delete=models.SET_WITH(<strong>get_new_owner</strong>)
)
因此,我们将在此处查看邀请,以找到要将对象转移到的用户。也许您需要从 .inivites
.
的集合中排除 get_new_owner
中事件的当前 .owner
与 一样,我们可以更好地使用 CASCADE 而不是显式删除 Event
对象,因为这将避免 User
删除触发 [=16] 的无限递归=] delete 可能会触发 User
delete:目前这是不可能的,但稍后如果实施额外的逻辑,可能会在这种情况下结束。在这种情况下,我们可以使用:
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:
<strong>CASCADE(collector, field, [obj], using)</strong>
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
<strong>return None</strong>
我有一个模型(事件),它有一个指向用户模型(事件的所有者)的外键。 此用户可以使用以下 ManyToManyField 邀请其他用户:
invites = models.ManyToManyField(
User, related_name="invited_users",
verbose_name=_("Invited Users"), blank=True
)
此邀请字段生成一个简单的 table,包含 ID、event_id 和 user_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
这会找到事件实例,returns 活跃的受邀用户按邀请 table ID 排序,因此我可以获得此查询集的第一项,它对应于第一个受邀用户.
为了运行删除用户时的功能,我使用了on_delete=models.SET:
owner = models.ForeignKey(User, related_name='evemt_owner', verbose_name=_("Owner"), on_delete=models.SET(get_new_owner()))
然后我运行陷入了一些问题:
- 它无法访问我传递的字段的 ID
- 我找不到将它用作 class 方法之类的方法,所以我不得不将函数放在模型之上。显然这意味着它不能再访问它下面的class,所以我尝试将事件模型作为函数的参数传递,但无法使其工作。
有什么想法吗?
首先,我们可以为 Owner
字段定义一个策略,该策略将使用已更新的对象调用该函数。我们可以定义这样的删除,比如在<i.app_name/deletion.py
文件中:
# app_name/deletion.py
def <strong>SET_WITH</strong>(value):
if callable(value):
def set_with_delete(collector, field, sub_objs, using):
for <strong>obj in sub_objs</strong>:
collector.add_field_update(field, value(<strong>obj</strong>), <strong>[obj]</strong>)
else:
def set_with_delete(collector, field, sub_objs, using):
collector.add_field_update(field, value, sub_objs)
set_with_delete.deconstruct = lambda: ('<em>app_name</em>.SET_WITH', (value,), {})
return set_with_delete
您应该将 callable 传递给 SET
,而不是调用该函数,因此您将其实现为:
from django.conf import settings
from django.db.models import Q
from <i>app_name</i>.deletion import <b>SET_WITH</b>
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:
<b>event.delete()</b>
class Event(models.Model):
# …
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='owned_events',
verbose_name=_('Owner'),
on_delete=models.SET_WITH(<strong>get_new_owner</strong>)
)
因此,我们将在此处查看邀请,以找到要将对象转移到的用户。也许您需要从 .inivites
.
get_new_owner
中事件的当前 .owner
与 Event
对象,因为这将避免 User
删除触发 [=16] 的无限递归=] delete 可能会触发 User
delete:目前这是不可能的,但稍后如果实施额外的逻辑,可能会在这种情况下结束。在这种情况下,我们可以使用:
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:
<strong>CASCADE(collector, field, [obj], using)</strong>
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
<strong>return None</strong>