【问题标题】:How to create a django form object for m2m through object如何通过对象为m2m创建django表单对象
【发布时间】:2016-06-02 15:26:03
【问题描述】:

我正在开发一个新的 django 项目,该项目具有使用“通过”对象的 m2m 关系。示例:

class Tag(models.Model):
    value = models.CharField(max_length=50, db_index=True)

class Photo(models.Model):
  tags = models.ManyToManyField(Tag, through='PhotoTag', related_name='tags', blank=True, db_index=True)

class PhotoTag(models.Model):
    photo= models.ForeignKey(Photo,db_index=True)
    tag = models.ForeignKey(Tag,db_index=True)
    added= models.DateTimeField(null=True, blank=True, auto_now_add=True)

我希望用户能够浏览充满照片的屏幕并添加/删除标签。我在为此设计表单/视图时遇到了一些麻烦。 我认为最好定义一个简单的表单对象来创建“PhotoTag”对象,然后使用包含所有 PhotoTagForm 对象的表单集创建一个 ListView,这些表单可能会或可能不会发布到视图以在 ListView 上进行实时更新,或者有一个保存按钮来保存所有更改。

我的问题是这个 PhotoTagForm 对象应该是什么样子? 我要使用 ModelForm 还是创建常规表单对象? 让我们假设表单对象继承自 Form 而不是 ModelForm。 表单需要处理添加(为照片添加标签)和删除(从照片中删除标签)。

【问题讨论】:

  • 我看不出通过phototag 定义M2M 的意义。似乎它只是增加了问题的开销。我认为不定义自己的throughobj 会更好地解决这个问题。
  • 这是一个简化版,直通对象中还有其他字段,一个重要的是添加字段,它跟踪它的创建,因此我可以显示“最近添加的标签”
  • 是否使用表单或模型表单主要是基于意见
  • 我明白了。我对 ModelForm 的理解是,基本上自动生成保存、is_valid、方法并根据模型自动添加字段。看起来这对于直通对象可能不是特别有利,因为字段的数量很少,并且可能需要手动自定义验证(获取有效的标签对象,在需要时创建新的对象)。我将修改我的问题以仅指定 Form 对象。
  • @e4c5 您是否知道任何关于通过对象使用 ModelForm 与 Form 进行 m2m 讨论的 SO 问题或其他信息?我只是好奇。自己找不到。

标签: django django-forms


【解决方案1】:

这就是我解决这个问题的方法:

# Forms.py:
class PhotoTagForm(forms.Form):

    tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(),required=False)

    photo=None
    initial_tags={}

    def __init__(self, *args, **kwargs):
        initial = kwargs.setdefault('initial', {})
        if kwargs.get('photo'):
            self.study=kwargs['photo']
            self.initial_tags = set([l for l in self.photo.tags.all()])
            initial['tags'] = self.initial_tags
        forms.Form.__init__(self, *args, initial=initial)

    def save(self,*args,**kwargs):

        print(self.cleaned_data.keys())

        if 'tags' in self.changed_data:
            submitted_tags=set(self.cleaned_data.pop("tags",[]))
            removed_tags=self.initial_tags.difference(submitted_tags)
            added_tags = submitted_tags.difference(self.initial_tags)
            # do logic with removed and added tags to update the m2m model

# views.py
def EditPhotoTagView(request,pk):
    photo = Photo.objects.get(pk=pk)
    if request.method == "POST" and 'save' in request.POST.keys():
        form = PhotoTagForm(request.POST,photo=photo)
        if form.is_valid():
            form.save()
    else:
        form = PhotoTagForm(photo=photo)

    return render(request, 'data/snippets/editm2m_form.html', {'form': form})

# urls.py
...
    url(r'^photo/(?P<pk>[0-9|.]+)/edit/tag$', EditPhotoTagView, name='photo_tag_form'),
...

这里的基本概念是您首先使用 m2m 对象的初始数据填充表单,在 POST 上您将 initial 与 form.cleaned_data 进行比较并执行必要的逻辑来更新 PhotoTag(创建或删除直通对象)。在这里,我使用了 url pk 中的照片,但您也可以在 photo.pk 中设置一个隐藏的输入字段,并在发布期间使用它来查找模型。我选择这种方式是因为将父对象作为属性然后直接对其进行操作更容易。 如果您将数据发布到 URL,这应该适用于您的列表视图,然后更新列表视图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多