简体   繁体   English

通过 ModelForm 的关系设置 Django M2M 的值

[英]Setting value of Django M2M through relationship via ModelForm

I am working on a set of product / category relationships in a Django application.我正在 Django 应用程序中处理一组产品/类别关系。

A product can belong to any category and needs to be ordered within that category, I am trying to do this using a Many to Many relationship with a "through=" option.产品可以属于任何类别,并且需要在该类别中订购,我试图使用“通过=”选项的多对多关系来做到这一点。

When a POST request is made via Ajax it takes the form of b'ordered_products=4&ordered_products=5' , I received an error straight after the forms __init__ call that "5 is not one of the available choices" where 5 is the valid id of an OrderedCategoryManagedProduct object.当通过 Ajax 发出 POST 请求时,它采用b'ordered_products=4&ordered_products=5'的形式,在表单__init__调用“5 不是可用选择之一”之后,我直接收到一个错误,其中 5 是一个OrderedCategoryManagedProduct对象。

models.py模型.py

class Category(models.Model):
    name = models.CharField(max_length=128)
    slug = models.SlugField(max_length=128, unique=True)


class Product(models.Model):
    name = models.CharField(max_length=128)
    category_management = models.ManyToManyField(
        Category,
        related_name="category_managed_products",
        through="OrderedCategoryManagedProduct",
        blank=True,
        verbose_name="Category Management",
    )


class OrderedCategoryManagedProduct(SortableModel):
    category = models.ForeignKey(
        Category, on_delete=models.CASCADE, related_name="cm_products"
    )
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="cm_categories"
    )

    class Meta:
        ordering = ["sort_order"]

    def get_ordering_queryset(self):
        return self.product.category_management()


class SortableModel(models.Model):
    sort_order = models.IntegerField(db_index=True, null=True)

    class Meta:
        abstract = True

views.py视图.py

# POST = <QueryDict: {'ordered_products': [5, 4]}>
@staff_member_required
@permission_required("menu.manage_menus")
def ajax_reorder_menu_items(request, category_pk):
    category = get_object_or_404(Category, pk=category_pk)
    form = ReorderCategoryProductsForm(request.POST, instance=category)
    status = 200
    ctx = {}
    if form.is_valid():
        form.save()
    elif form.errors:
        status = 400
        ctx = {"error": form.errors}
    return JsonResponse(ctx, status=status)

forms.py表格.py

class ReorderCategoryProductsForm(forms.ModelForm):
    ordered_products = OrderedModelMultipleChoiceField(
        queryset=OrderedCategoryManagedProduct.objects.none()
    )

    class Meta:
        model = Category
        fields = ["id"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance:
            self.fields["ordered_products"].queryset = self.instance.cm_products.all()
        pass

    def save(self):
        for sort_order, category in enumerate(self.cleaned_data["ordered_products"]):
            category.cm_products.sort_order = sort_order
            category.save()
        return self.instance


class OrderedModelMultipleChoiceField(forms.ModelMultipleChoiceField):
    def clean(self, value):
        qs = super().clean(value)
        keys = list(map(int, value))
        return sorted(qs, key=lambda v: keys.index(v.pk))

Big thanks to the #django IRC channel for the help on this, if anyone suffers the same problem the correct code was as follows:非常感谢#django IRC 频道对此的帮助,如果有人遇到同样的问题,正确的代码如下:

class ReorderCategoryProductsForm(forms.ModelForm):
    ordered_products = OrderedModelMultipleChoiceField(
        queryset=OrderedCategoryManagedProduct.objects.all()
    )

    class Meta:
        model = Category
        fields = ["id"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance:
            self.fields["ordered_products"].queryset = self.instance.cm_products.all()
        pass

    def save(self):
        for sort_order, ocmp in enumerate(self.cleaned_data["ordered_products"]):
            ocmp.sort_order = sort_order
            ocmp.save()
        return self.instance

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM