Django多对多关系不储蓄

2024-09-24 22:19:21 发布

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

更新

对于任何好奇的人,我想知道什么,为什么和如何修复它。 在我看来: fields = ['html', 'tags', 'title', 'text', 'taken_date', 'image'] 我正在使用{表格as\p}}在我的模板中。显然,一旦它从表单中发布,它真的,真的不希望任何其他东西触及表单中不存在的字段。 所以我把“标签”字段从我的视图中去掉了,它起作用了。在

感谢所有回应的人。在

原始问题

使用Django 2.0.1和postgresql9.2.18

我在写一个简单的photogallery应用程序。在里面我有一个photo对象和PhotoTag对象。照片可以有许多标签,并且标签可以与许多照片相关联,因此它需要是一个多个字段。在

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

照片保存得很好,update_标签被称为fine,标签从照片中读取,标签被保存到PhotoTag fine中。但是将这两个连接在一起的manytomy表并不能插入新行。除非代码在update_tags函数或post_save receiver函数期间异常退出,否则将调用update_tags之后的thumbs。在

我甚至试过用连接.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)

更新:

^{pr2}$

Tags: instancetextimageselftruedatemodelssave
2条回答

重写保存方法,如下所示

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)

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

发生这种情况的原因是在docs处,更明确地说是在this ticket处(使用代码)。在

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

  • 一个黑客的解决方案是使用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,一个更合理的解决方案是使用^{}信号,如前所述in this post或前面提到的ticket

  • 最好的方法是ditch the signals并在使用ModelForm()的情况下重写ModelForm().clean()方法,如果直接保存模型,也重写Model().save()方法。在

    一个ModelForm().instance.my_flag将很有用,因此您可以检查Model().save()中是否存在{},以避免访问两次数据库。

相关问题 更多 >