python - Django 多对多关系不保存

标签 python django postgresql manytomanyfield

更新:

对于任何好奇的人,我想出了解决它的原因、原因和方法。 在我看来,我有: fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image'] 并在我的模板中使用 {{ form.as_p }}。显然,一旦从表单中发布,它真的、真的不希望任何其他内容触及表单中不存在的表单字段。 所以我从我的 View 中删除了“标签”字段,它起作用了。

感谢所有回复的人。

原始问题:

使用 Django 2.0.1 和 PostgreSQL 9.2.18

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

保存提交的照片后,post_save 接收器调用函数制作缩略图(效果很好)和更新标签的函数。

照片可以很好地保存,update_tags 可以很好地调用,标签可以很好地从照片中读取,标签可以很好地保存到 PhotoTag 中。但是将两者捆绑在一起的 manytomany 表并没有插入新行。除非代码在 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

最佳答案

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

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

当保存一个ModelForm()时(在后台点击保存),首先保存对象的一个​​实例,然后触发它的所有信号等等。第三步是保存所有m2m关系使用 ModelForm().cleaned_data。如果 ModelForm().cleaned_data['tags']None,则从您的信号创建的所有关系都将被删除。

  • 一个骇人听闻的解决方案是使用一个带有transaction.on_commit()post_save 信号。将现有事务(包括保存所有m2m关系的过程)提交到数据库后执行相关代码。

    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)
    
  • 如果您的多对多关系没有 blank=True,一个更合理的解决方案是使用 m2m_changed()信号,如解释的那样in this post或之前提到的 ticket .

  • 最好的是ditch the signals并在使用 ModelForm() 的情况下覆盖 ModelForm().clean() 方法,同时覆盖 Model().save() 方法,以防直接保存模型。

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

关于python - Django 多对多关系不保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48450004/

相关文章:

python - 列表复制不起作用?

postgresql - 如何使 Microstrategy 与 Redshift/psql 表中的用户模式一起工作?

python - 如何在 Python 中检查对 Google Appengine 的传入请求的 HTTP header ?

python - 如何使用scrapy获取href及相关信息?

python - 上传文件在 Django 中无法正常工作

python - django 从查询集中返回外键对象?

python - 在给定时间内禁用 django 表单字段

android - 是否有用于从 PostgreSQL 数据库呈现 OpenStreetMap 数据的 API?

sql - 如何在 PostgreSQL 中使用 case 获取多个记录?

Python 将大型 numpy 数组转换为 pandas 数据框