Django:ManyToManyField,如果对象不存在则添加它

Posted

技术标签:

【中文标题】Django:ManyToManyField,如果对象不存在则添加它【英文标题】:Django: ManyToManyField, add object if it doesn't already exist 【发布时间】:2012-04-24 08:25:26 【问题描述】:

我正在尝试在 Django 中使用 ModelForms 将内容添加到我的数据库中,其中包括 ManyToManyField。这是我的模型的相关部分:

class Category(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()

    def __unicode__(self):
        return self.name

class Recipe(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to='images/recipethumbs/', null = True, blank=True)
    ingredients = models.ManyToManyField(Ingredient, through="IngredientMap")
    categories = models.ManyToManyField(Category)
    citation = models.CharField(max_length=200)

    def __unicode__(self):

默认情况下,ManyToManyFields 由多项选择表示。这允许用户从类别对象中预先存在的字段中选择。我想更改此设置,以便用户可以选择当前存在的类别,或者如果不存在则添加新类别。这似乎可以通过将小部件更改为 TextInput 来完成。

class RecipeForm(ModelForm):
    class Meta:
        model = Recipe
        widgets = 
            'categories': TextInput(attrs='size': 40,),
            'ingredients': Textarea,
        

但是,如果用户输入了类别表中当前不存在的类别,那么 Django 会抱怨我需要“输入值列表”。如果新类别尚不存在,我如何获取表单以添加

按照 Ilvar 的建议,我在自定义 .save() 中的解决方案:

categories = re.findall(r'\w+[\w\s]+', self.cleaned_data.get('categories')) #returns an array

        if commit:
            m.save()

        # You can only assign m2m if the Recipe object has been saved.
        for category in categories:
            try:
                category_in_db = Category.objects.get(name=category)
            except:
                category_in_db = None
            if category_in_db:
                m.categories.add(category_in_db)
            else:
                m.categories.create(name=category)

        return m

【问题讨论】:

在这种情况下,您希望 django 知道如何处理来自文本输入的数据?您的 Category 模型有一个必需的描述字段作为开始,因此即使使用自定义小部件,这个问题实际上也无法解决。 我不希望它知道如何处理它。我想告诉它该怎么做,如果我知道如何... 【参考方案1】:

您需要在表单中添加exclude m2m 字段并手动添加CharField 以形成类本身。然后覆盖__init__ 以在initialsave 中设置此字段。在save 中,您可以对cleaned_data 中的文本执行任何操作。我想,在你的情况下,它将用逗号分割它,为每个值创建一个类别,并在保存父表单之后将类别列表分配给对象中的字段,然后再返回结果。也许还可以添加一些autocomplete 以避免在客户端输入错误。

【讨论】:

啊,我明白了。这就说得通了。谢谢伊尔瓦。

以上是关于Django:ManyToManyField,如果对象不存在则添加它的主要内容,如果未能解决你的问题,请参考以下文章

Django OneToOneField、ManyToManyField、外键

关于 django ManyToManyField

Django:如何检查用户是不是已经在 ManyToManyField 上投票?

使用自定义字段扩展 Django 的 ManyToManyField

删除 django 模型中不相关的对象(manytomanyfield)

Django 1.8 - 中间多对多关系 - 使用“ManytoManyField”的结果是啥?