使用django modelform进行自定义数据强制

使用django modelform进行自定义数据强制,django,django-forms,custom-widgets,Django,Django Forms,Custom Widgets,警告:我的知识不深,所以如果我找错了人,请告诉我 无论如何,我正在写一个标签应用程序。我希望用户能够输入一个空格分隔的单词列表,而不必浏览一个巨大的标签列表 有两种模式。一个保存标记的名称,另一个保存标记分配 class Tags(models.Model): name = models.CharField(max_length=50) def __unicode__(self): return self.name class Tagged(models.Mo

警告:我的知识不深,所以如果我找错了人,请告诉我

无论如何,我正在写一个标签应用程序。我希望用户能够输入一个空格分隔的单词列表,而不必浏览一个巨大的标签列表

有两种模式。一个保存标记的名称,另一个保存标记分配

class Tags(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

class Tagged(models.Model):
    tag = models.ForeignKey(Tags)
    app = models.CharField(max_length=256)
    app_item = models.IntegerField()
modelform只显示标记字段,因为这是用户唯一需要的输入

class TaggedForm(forms.ModelForm):
    class Meta:
        model = Tagged
        fields = ('tag',)
        widgets = {
            'tag': TextInput(),
        }
我遇到的问题是,虽然我能够输入一个以空格分隔的选项列表,但输入被视为无效而拒绝

选择一个有效的选项。该选择不是可用的选择之一

我想做的是获取数据,强制将其转换为有效的选项,并将清理后的数据作为选项字段返回(即:获取意外和用户友好的内容,并使其符合预期和django友好)

我的问题是,我如何做到这一点,并尽可能简单

谢谢

编辑:

该解决方案遵循Tisho的建议

数据在表单中被清除,并且自定义保存函数处理保存,因此应用程序只需要传入几个变量。它的边缘仍然有点粗糙(例如没有权限),但它可以工作

class TaggedForm(forms.Form):
    tags = forms.CharField(max_length=50)

    def save(self, app, app_item, tags):

        # Convert tag string into tag list (whitespace and duplicates are removed here)
        split_tags = list(set(tags.strip().split(' ')))
        tag_list = []
        for tag in split_tags:
            if tag != ''  and tag != u'':
                tag_list.append(tag)

        # Get list of current tags
        current_tags = Tagged.objects.filter(app=app, app_item=app_item)

        # Separate new, stable, and old tags
        # (stable tags are deleted from tag_list leaving it populated by only new tags)
        old_tags = []
        if current_tags:
            for tag in current_tags:

                # Stable tags
                if str(tag.tag) in tag_list:

                    # Delete tag from tag_list (this removes pre-existing tags leaving just new tags)
                    del tag_list[tag_list.index(str(tag.tag))]

                # Old tags
                elif not str(tag.tag) in tag_list:
                    old_tags.append(tag.tag)

        # Remove old tags
        try:
            Tagged.objects.filter(tag__in=old_tags).delete()
        except Tagged.DoesNotExist:
            pass

        # Add new tags
        for tag in tag_list:

            # Get tag object
            try:
                tag=Tags.objects.get(name=tag)
                tag.save()

            # Create new tag
            except Tags.DoesNotExist:
                tag = Tags(name=tag)
                tag.save()

            # Add new tagging relationship
            try:
                new_tag = Tagged(tag=tag, app=app, app_item=app_item)
                new_tag.save()
            except Tags.DoesNotExist:
                pass

    def clean(self):

        # Get tags
        try:
            tags = self.cleaned_data['tags'].strip().split(' ')
        except KeyError:
            tags = False

        # Process tags
        if tags:

            # Variables
            tag_list = ''

            # Build tag list
            for tag in tags:
                if tag != '' or tag != u'':
                    tag_list += tag + ' '

            # Assign and return data
            self.cleaned_data['tags'] = tag_list
            return self.cleaned_data

        # Just return cleaned data if no tags were submitted
        else:
            return self.cleaned_data    
用法:标记逻辑被排除在应用程序逻辑之外

tagged_form = TaggedForm(request.POST)
if tagged_form.is_valid():
    tagged_form.save('articles', 1, request.POST.get('tags',''))

只要您只需要这里的标签列表,就不需要
forms.ModelForm
。ModelForm将尝试创建一个模型(标记)实例,因此它需要所有字段-
app
app\u item
。一个简单的表单就可以了:

class TagsForm(forms.Form):
    tags = forms.CharField(max_length=200)
在视图中,只需处理表单:

if request.POST:
    form = TagsForm(request.POST)
    if form.is_valid():
        tags = form.cleaned_data['tags'].split(' ')
        # here you'll have a list of tags, that you can check/map to existing tags in the database(or to add if doesn't exist.. some kind of pre-processing).
我不知道您的真正目标是什么,但从这里您可以显示第二种形式:

class TaggedForm2(forms.ModelForm):
    class Meta:
        model = Tagged
从用户输入中获取标记后,要创建新表单:

form = TaggedForm()
form.fields['tag'].widget = forms.widgets.SelectMultiple(choices=((t.id, t.name) 
                            for t in Tags.objects.filter(name__in=tags))) 

我不确定这是否接近您需要的,只是在这里添加一些示例。

只要您在这里只需要一个标记列表-您不需要
forms.ModelForm
。ModelForm将尝试创建一个模型(标记)实例,因此它需要所有字段-
app
app\u item
。一个简单的表单就可以了:

class TagsForm(forms.Form):
    tags = forms.CharField(max_length=200)
在视图中,只需处理表单:

if request.POST:
    form = TagsForm(request.POST)
    if form.is_valid():
        tags = form.cleaned_data['tags'].split(' ')
        # here you'll have a list of tags, that you can check/map to existing tags in the database(or to add if doesn't exist.. some kind of pre-processing).
我不知道您的真正目标是什么,但从这里您可以显示第二种形式:

class TaggedForm2(forms.ModelForm):
    class Meta:
        model = Tagged
从用户输入中获取标记后,要创建新表单:

form = TaggedForm()
form.fields['tag'].widget = forms.widgets.SelectMultiple(choices=((t.id, t.name) 
                            for t in Tags.objects.filter(name__in=tags))) 

我不确定这是否接近您的需要,只是在这里添加一些示例。

我的目标是尽可能使标记不受应用程序的影响,以便我可以轻松地将其用于其他应用程序(即:将标记代码保留在应用程序之外)。我想我能做的就是把转换和保存函数放到form类中,让应用程序调用这些函数。我的目标是尽可能使标记不受应用程序的影响,这样我就可以轻松地将其用于其他应用程序(即:将标记代码排除在应用程序之外)。我想我能做的就是把转换和保存函数放到form类中,让应用程序调用这些函数。我来试一试,然后回来报告。