将ManyToMany字段的Widget自定义为具有循环ForeignKey的Model

use*_*631 5 django django-forms django-widget

我有两个型号分类和产品.

  • 产品可以有多个类别
  • 一个类别可以有多个产品.
  • 类别具有循环外键,本身.
  • 并非所有类别都具有相同的深度级别

例:

  • A类
    • A_1类
    • 类别A_2
      • 类别A_2_1
  • B类
  • C类
    • C_1类

models.py

class Product:
    categories = models.ManyToManyField(Category)
    name = models.CharField(max_length=255)

class Category:
    categories = models.ForeignKey(self)
    name = models.CharField(max_length=255)
Run Code Online (Sandbox Code Playgroud)

作为表单我使用ModelForm:

class ProductForm(ModelForm):
    class Meta:
        model = Product
        fields = ['categories', 'name', 'short_description', 'description']
        widgets = {
            'categories': MyWidget,
        }
Run Code Online (Sandbox Code Playgroud)

我想要实现的目标:

我想实现条件选择(窄选项)在产品表单创建上:

  1. 只有顶级父类别(级别0 A,B,C)可用
  2. 用户选择父类别.如果父母有孩子,他的孩子会出现一个新的选择框(类别1 A1,C1)
  3. 用户选择1级类别(A1,C1).如果父母有孩子,他的孩子会出现一个新的选择框(2级A2)

    • 重复该过程,直到没有子项可用(递归),用户选择树中的"最小"类别
    • 用户可以使用新按钮添加更多类别并再次启动1-3流程
    • 我想做选择,使用JavaScript添加新选择
    • 在表单提交我想只发送最后的子类别

选项我想:

  1. 更改ManyToMany相应的默认字段 - 看起来没有好的挂钩和/或继承
  2. 使用ManytoMany的非默认自定义字段instean(如Charfield) - 在清理,保存表单上更复杂
  3. 更改/继承小部件.我的问题是如何在提交时将数据发送到默认字段,并在编辑时显示/显示它

实用,假设我有7个选择框,每个框的值都是:

  1. Parent1-> Child11-> Child111
  2. Parent2-> Child21
  3. Parent3-> Child31-> Child311

如何告诉Django浏览器提交(以及其他数据)发送给ManyToMany的所有三个中的最后一个Child

我可以用Javascript收集它们,但我必须告诉Django获取这些数据,这就是你需要的.

我需要一些帮助作为代码和指示如何做到这一点.

在此输入图像描述

Col*_*ole 2

Django 允许您将引用的模型定义为ForeignKeyManyToManyField作为\'<app_name>.<model_name>\'字符串,而不必导入模型并直接分配它。这解决了很多问题,特别是循环导入。

\n\n
\n\n

categories假设您拥有带有Category模型和products模型的应用程序Product,则:

\n\n

products/models.py:

\n\n
class Product:\n    categories = models.ManyToManyField(Category)\n    name = models.CharField(max_length=255)\n
Run Code Online (Sandbox Code Playgroud)\n\n

categories/models.py:

\n\n
class Category:\n    categories = models.ManyToManyField(self)\n    name = models.CharField(max_length=255)\n
Run Code Online (Sandbox Code Playgroud)\n\n

可以直接翻译成你需要的:

\n\n

products/models.py:

\n\n
class Product:\n    categories = models.ManyToManyField(\'categories.Category\')\n    name = models.CharField(max_length=255)\n
Run Code Online (Sandbox Code Playgroud)\n\n

categories/models.py:

\n\n
class Category:\n    categories = models.ManyToManyField(\'self\')\n    name = models.CharField(max_length=255)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样,您就可以拥有任意数量的类别:

\n\n
category_one = Category.create(name=\'Category one\')\ncategory_two = Category.create(name=\'Category two\')\ncategory_three = Category.create(name=\'Category three\')\ncategory_three.categories.add(category_one, category_two)\nsome_product = Product.create(name=\'Test Product\')\nsome_product.categories.add(category_three)\n
Run Code Online (Sandbox Code Playgroud)\n\n

多对多字段文档

\n\n
\n\n

同样重要的是要注意,对于任何 Python 类,self类本身不是 \xe2\x80\x93,而是实例。所以你不能在实例方法之外引用它,这里有一个很好的解释。该字符串在这里起作用的唯一原因\'self\'是 Django 将其转换为它所在的类,categories.Category\xe2\x80\x93\xe2\x80\x93 因此,将其替换为显式可能是一个好self主意\'categories.Category\'

\n