Django多对多关系没有保存

时间:2018-01-25 18:55:36

标签: python django postgresql manytomanyfield

更新

对于任何好奇的人,我想出了什么,为什么以及如何解决它。 在我看来,我有: fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image'] 我在我的模板中使用{{form.as_p}}。显然,一旦从表单中发布它真的,实际上不希望任何其他任何东西触及表单中尚未出现的表单字段。 所以我从我的视图中取出了“标签”字段,然后就可以了。

感谢所有回复的人。

原始问题

使用Django 2.0.1和PostgreSQL 9.2.18

我正在写一个简单的照相馆应用程序。在其中我有一个照片对象和PhotoTag对象。照片可以有很多标签,标签可以与许多照片相关联,因此它需要是一个ManyToManyField。

保存提交的照片后,post_save接收器调用函数来制作缩略图(工作正常)和更新标记的函数。

照片保存得很好,update_tags被称为正常,标签可以从照片中读取,标签可以保存到PhotoTag中。但是将两者捆绑在一起的许多表并没有插入新的行。除非代码在update_tags函数或post_save接收函数期间异常退出,否则将调用update_tags之后的拇指。

我甚至尝试使用connection.cursor直接写入m2m表,它具有相同的行为。

如果我再次尝试在Photo对象上调用save(),我会因为post_save信号而进入无限循环。

我对发生了什么感到困惑。有线索吗?

# models.py

def update_tags(instance):
    tags = get_tags(instance.image)

    # Set initial values
    pt = []
    tagid = ''
    photoid = instance.id

    # Loop through tag list and insert into PhotoTag and m2m relation
    for x in range(0, len(tags)):
        # Make sure this tag doesn't already exist
        if PhotoTag.objects.filter(tag_text=tags[x]).count() == 0:
            pt = PhotoTag.objects.create(tag_text=tags[x])
            tagid = PhotoTag.objects.latest('id').id
            instance.tags.add(pt)
        else:
            # Only working with new tags right now
            pass

    return


class Photo(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               on_delete=models.CASCADE)
    title = models.CharField(max_length=200, null=True, blank=True)
    text = models.TextField(null=True, blank=True)
    html = models.BooleanField(default=False)
    filename = models.CharField(default='', max_length=100, blank=True,
                                null=True)
    image = models.ImageField(upload_to=upload_path)
    location = models.CharField(max_length=100, blank=True, null=True)
    entry_date = models.DateTimeField(default=timezone.now)
    taken_date = models.DateTimeField(blank=True, null=True)

    tags = models.ManyToManyField(PhotoTag, blank=True)


@receiver(post_save, sender=Photo)
def thumbs(sender, instance, **kwargs):
    """
    Upon photo save, create thumbnails and then
    update PhotoTag and m2m with any Exif/XMP tags
    in the photo.
    """

    mk_thumb(instance.image, 'mid')
    mk_thumb(instance.image, 'th')
    mk_thumb(instance.image, 'sm')

    update_tags(instance)

    return

-------------
From views.py
-------------

class PhotoCreate(LoginRequiredMixin, CreateView):
    model = Photo
    template_name = 'photogallery/photo_edit.html'
    fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image']

    def get_initial(self):
        self.initial = {'entry_date': timezone.now()}
        return self.initial

    def form_valid(self, form):
        form.instance.author = self.request.user

        return super(PhotoCreate, self).form_valid(form)

更新

def save(self, mkthumb='', *args, **kwargs):
      super(Photo, self).save(*args, **kwargs)
      if mkthumb != "thumbs":
          self.mk_thumb(self.image, 'mid')
          self.mk_thumb(self.image, 'th')
          self.mk_thumb(self.image, 'sm')

          self.update_tags()

          mkthumb = "thumbs"

      return

2 个答案:

答案 0 :(得分:0)

覆盖您的保存方法,如

def save(self, *args, **kwargs):
    tags = get_tags(self.image)

    # Set initial values
    pt = None

    # Loop through tag list and insert into PhotoTag and m2m relation
    for x in range(0, len(tags)):
        # Make sure this tag doesn't already exist
        if PhotoTag.objects.filter(tag_text=tags[x]).count() == 0:
            pt = PhotoTag.objects.create(tag_text=tags[x])
            self.tags.add(pt)
        else:
            # Only working with new tags right now
            pass
      super(Photo, self).save(*args, **kwargs)

答案 1 :(得分:0)

我有一个similar issue,在保存用户实例时我试图在其中添加组。

发生这种情况的答案在docs,更明确地(使用代码)在this ticket

保存ModelForm()时(在管理员中单击保存),首先保存对象的一个​​实例,然后触发其所有信号,等等。第三步是使用{{1}保存所有m2m关系。 }。如果ModelForm().cleaned_dataModelForm().cleaned_data['tags'],则将从您的信号创建的所有关系都将被删除。

  • 一个棘手的解决方案是使用带有transaction.on_commit()None信号,该信号将在现有事务(包括保存所有m2m关系的过程)被提交后执行相关代码。数据库。

    post_save
  • 如果您的多对多关系还没有def on_transaction_commit(func): ''' Create the decorator ''' def inner(*args, **kwargs): transaction.on_commit(lambda: func(*args, **kwargs)) return inner @receiver(post_save, sender=Photo) @on_transaction_commit def tags(instance, raw, **kwargs): """ Create the relevant tags after the transaction of instance is committed, unless the database is populated with fixtures. """ if not raw: update_tags(instance) ,更合理的解决方案是使用m2m_changed()信号,如in this post或前面提到的ticket所述

  • 最重要的是,在使用blank=True的情况下,ditch the signals并覆盖ModelForm().clean()方法,并且也覆盖ModelForm()方法如果直接保存模型。

    Model().save()很有用,因此您可以在ModelForm().instance.my_flag中检查现有的Model().my_flag,以避免访问数据库两次。