【问题标题】:How to get the user from a manytomanyfield in Django using Django singals and creating another object with the recived manytomany user field如何使用 Django 信号从 Django 中的 manytomanyfield 获取用户并使用接收到的 manytomany 用户字段创建另一个对象
【发布时间】:2019-11-11 21:51:32
【问题描述】:

我想知道有什么方法可以使用信号在一个模型中获取更新的多对多字段并将它们发布到另一个模型

class Post(models.Model):

    name=models.CharField(max_length=24)
    nc=models.ManyToManyField(settings.AUTH_USER_MODEL)
    def __str__(self):
        return self.name
        # return self.name
m2m_changed.connect(receiver=like_post,sender=Post.nc.through)

我想在 post 模型的 nc 字段中收集更新的记录并使用信号我想使用函数创建一个对象 这是连接到 Post 模型的信号

def like_post(sender, *args, **kwargs):
    # if kwargs['action'] in ('post_update'):
    if kwargs['action'] in ('post_add', 'post_remove','post_update'):

        print(kwargs['instance'])
        instance = kwargs['instance']
        print(instance)
        notify = Notify.objects.create(
                 recipient=instance,
                 creator=Post.objects.get(pk=50),
                  state='unread',
                   type=kwargs['action'],
                )
    else:
        print('no instance') 

在收件人和创建者部分,我想使用现有用户对象更新这些字段,创建者是更新多多字段的人,收件人是创建该帖子的人

notify model:
class Notify(models.Model):
    recipient = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='notify_recipient',on_delete=models.CASCADE)
    creator = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='notify_sender',on_delete=models.CASCADE)
    state = ('read', 'unread', 'unseen')
    type = models.CharField(max_length=30, blank=True)
    url = models.CharField(max_length=50, blank=True)

每当我运行它时,实例只会打印帖子对象名称并触发此错误

ValueError at /admin/posts/post/50/change/
Cannot assign "<Post: ok>": "Notify.recipient" must be a "User" instance.

【问题讨论】:

  • 正如错误所说,收件人是用户的外键。你为什么要在那里分配一个帖子?
  • 不,问题不在于错误,我想知道如何通过信号将外键用户(代替收件人)从 post 模型中的 manytomanyfield 发送到该对象

标签: python django django-models django-views django-signals


【解决方案1】:

您可以看到您的 Notify 类将 receipent 定义为 AUTH_USER_MODEL 的 ForeignKey 元素,但您正在创建一个 Notify您的信号为:

notify = Notify.objects.create(
                 recipient=instance,
                 creator=Post.objects.get(pk=50),
                  state='unread',
                   type=kwargs['action'],
                )

这里,instancePost 的实例,而不是User,而且您也在创建者字段中使用post 实例。这就是导致错误的原因。

要解决此错误,您需要在这些字段中传递用户实例。例如,您可以使用以下内容:

notify = Notify.objects.create(
                     recipient=instance.nc, # find out how to pass the user of the post here
                     creator=Post.objects.get(pk=50), # replace by an user instance here instead of a post instance 
                      state='unread',
                       type=kwargs['action'],
                    )

编辑: 为确保保存用户实例,您需要将 ModelAdmin 的 save_model 方法覆盖为 post 模型:

class PostAdmin(admin.ModelAdmin):
    def save_related(self, request, form, formsets, change):
    if not form.cleaned_data['nc']:
        form.cleaned_data['nc'] = [request.user]
    form.save_m2m()

【讨论】:

  • 无法分配“.ManyRelatedManager object at 0x06E5E150>”:“Notify.recipient”必须是“User”实例,我得到了现在出现这个错误
  • 当我打印 instance.nc 时,终端显示为 auth.User.None
  • 这是因为即使保存了帖子实例,它的用户实例也不会立即保存。因此,首先您需要确保在执行信号之前保存 nc 的数据。在使用多对多字段的大多数情况下都会出现此错误。
  • 我部分理解了它,但我不明白只有在该帖子模型的 nc 已更改时才会触发信号的一件事,对吗?所以在那种情况下为什么它没有显示更新的用户,你能详细说明解决这个问题的可能方法吗
  • 我不明白您在此处使用 m2m_changed 信号的问题。您说正确的是,仅当该帖子模型的 nc 已更改时才会触发信号。因此,考虑通过更改任何其他字段而不是 nc 来激活信号是没有用的。
猜你喜欢
  • 2021-10-30
  • 2018-01-30
  • 2019-01-04
  • 2011-06-06
  • 2014-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多