Установка значения Django M2M через отношение через ModelForm - PullRequest
0 голосов
/ 13 января 2020

Я работаю над набором отношений продукта / категории в приложении Django.

Продукт может принадлежать к любой категории и его необходимо заказать в этой категории, я пытаюсь сделать это с помощью Отношение «многие ко многим» с параметром «through =».

Когда запрос POST выполняется через Ajax, который принимает форму b'ordered_products=4&ordered_products=5', я получил ошибку сразу после вызова форм __init__ что «5 не является одним из доступных вариантов», где 5 - действительный идентификатор объекта OrderedCategoryManagedProduct.

models.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

# 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

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))

1 Ответ

0 голосов
/ 13 января 2020

Большое спасибо каналу # django IR C за помощь в этом, если кто-то испытывает ту же проблему, правильный код был следующим:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...