ModelForm مع علاقة أطراف بأطراف: كيفية إنشاء إدخالات جديدة تلقائيًا إذا لزم الأمر؟

0

لدي نموذجان بعلاقة ManyToMany:

class Topping(models.Model):
    name = models.CharField(max_length=200)

class Pizza(models.Model):
    name = models.CharField(max_length=200)
    toppings = models.ManyToManyField(Topping, blank=True)

لدي هذا النموذج لتحديث بيتزا:

class PizzaUpdateForm(forms.ModelForm):
    class Meta:
        model = Pizza
        fields=('name', 'toppings')
        widgets={'toppings': Select2TagWidget}

ال Select2TagWidget يتم استيراده من django_select2 . أرغب في استخدامه للسماح بإنشاء بيتزا ديناميكية (يبدو رائعًا ، أليس كذلك؟).

يتم استخدام هذا النموذج من خلال هذا العرض:

def update_pizza(request, pk):
    pizza = Pizza.objects.get(pk=pk)
    if request.method == 'POST':
        form = PizzaUpdateForm(request.POST, instance=pizza)
        if form.is_valid():
            form.save()
    else:
        form = PizzaUpdateForm(instance=pizza)
    return render(request, 'pizza/pizza_form.html',
                  {'form': form, 'pizza': pizza})

في الوقت الحالي ، يعمل على الإضافات المسجلة مسبقًا ، لكني أود السماح للمستخدمين بتعريف الإضافات الجديدة عبر هذا النموذج نفسه ، ولهذا السبب أستخدم select2 في المقام الأول. لسوء الحظ ، لا يتحقق النموذج من صحة ذلك إذا قمت بذلك الآن ، وهو أمر متوقع.

إذا حاولت إضافة عملية حظر غير مشروعة ، فإليك ما يحدث:

"illegal_topping" is not a valid value.

أعتقد أنني بحاجة إلى التكرار form['toppings'].value() في ال if request.method == 'POST' حظر قبل استدعاء form.is_valid () لإنشاء الطبقة الجديدة باستخدام get_or_create أو شيئا من هذا القبيل.

ومع ذلك ، إذا فعلت ذلك ، فإن القيم هي مزيج من معرفات الطبقة الحالية وأسماء الطبقة الجديدة. كل شيء عبارة عن سلسلة ، لذلك لست متأكدًا من كيفية تقييم أي من الإضافات الجديدة وأي منها كان موجودًا مسبقًا.

ربما سيكون من الرائع إذا كانت هذه القيم تتكون فقط من أسماء الطبقة ، لكني لا أعرف كيفية تحقيق ذلك.

ربما يكون نهجي خاطئًا تمامًا لأنني جديد في تطوير الويب و Django على وجه الخصوص ، لذلك أود حقًا أن يكون لديك مدخلات في هذا الأمر. يبدو لي أن هذا يجب أن يكون مشكلة شائعة نسبيًا ... ولكن لم أتمكن من العثور على (أو فهم) المساعدة. أعلم أنه يجب أن تكون هناك بعض مشاكل M2M التي لا أتوقعها ، لذا فإن أي توجيهات مرحب بها.

2 الاجابة

0

لقد وجدت طريقة قذرة.

class PizzaUpdateForm(forms.ModelForm):
    class Meta:
        model = Pizza
        fields=('name', 'toppings')
        widgets={'toppings': Select2TagWidget}

    toppings = forms.ModelMultipleChoiceField(queryset=Topping.objects.all(),
                                              to_field_name='name',
                                              widget=Select2TagWidget,
                                              required=False)

def update_pizza(request, pk):
    pizza = Pizza.objects.get(pk=pk)
    if request.method == 'POST':
        form = PizzaUpdateForm(request.POST, instance=pizza)
        for topping_name in form['toppings'].value():
            topping, created = Topping.objects.get_or_create(name=topping_name)
            if created: topping.save()
        if form.is_valid():
            form.save()
    else:
        form = PizzaUpdateForm(instance=pizza)
    return render(request, 'pizza/pizza_form.html',
                  {'form': form, 'pizza': pizza})

ومع ذلك ، أشعر أنه سيكون أفضل إذا لم يكن منطق الإبداع في المنظر ولكن في pizza.forms وحدة. هذا ما ستفعله الآن.

:مؤلف
0

أعتقد أنك تسمح للمستخدمين إما باختيار الإضافات التي تخرج بالفعل أو يمكنهم إنشاء واحدة جديدة ، أليس كذلك؟ (create_top هو اسم المدخلات التي تقدم فيها طلبات المستخدم للتصدر الجديد)

def update_pizza(request, pk):
    pizza = Pizza.objects.get(pk=pk)
    if request.method == 'POST':
        form = PizzaUpdateForm(request.POST, instance=pizza)
        if form.is_valid():
            ctoppings = []

            form = form.save(commit=False)
            if not request.POST.get['create_top'] = '':
                t, create = Topping.objects.get_or_create(name = request.POST.get['create_top'])
                temp_top = request.POST.getlist('toppings')
                for top in temp_top:
                    ctop = Topping.objects.get(name=top)
                    ctoppings.append(ctop)
                ctoppings.append(t)
                form.toppings.set(ctoppings)
            form.save()
    else:
        form = PizzaUpdateForm(instance=pizza)
    return render(request, 'pizza/pizza_form.html',
                  {'form': form, 'pizza': pizza})

انظر ما إذا كان هذا يمكن أن يساعدك.

:مؤلف

أسئلة ذات صلة

فوق
قائمة طعام