如何通过对象

时间:2016-06-02 15:26:03

标签: django django-forms

我正在开发一个新的django项目,该项目的m2m关系使用' through'宾语。例如:

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对象的formset创建一个ListView,这些表单可能会或可能不会POST到视图以便在ListView上进行实时更新,或者只有一个保存按钮来保存所有更改。

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

1 个答案:

答案 0 :(得分: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,那么这应该适用于您的列表视图,然后更新列表视图。