জ্যাঙ্গো - ক্রিয়েটভিউ নেস্টেড ফর্মসেটের সাহায্যে ফর্ম সংরক্ষণ করছে না


14

আমি জ্যাঙ্গো-ক্রিস্পি-ফর্ম লেআউট বৈশিষ্ট্যটি ব্যবহার করে নেস্টেড ফর্মসেটগুলি মূল ফর্মের সাথে সঞ্চয় করার জন্য একটি দৃষ্টিভঙ্গি মানিয়ে নেওয়ার চেষ্টা করছি তবে আমি এটি সংরক্ষণ করতে পারি না। আমি এই কোড উদাহরণ প্রকল্পটি অনুসরণ করছি কিন্তু ডেটা সংরক্ষণের জন্য ফর্মसेटটি বৈধতা পেতে পারি নি। কেউ যদি আমার ভুলটি উল্লেখ করতে পারে তবে আমি সত্যিই কৃতজ্ঞ হব। এমপ্লয়িফর্মের জন্যও একই দর্শনটিতে আমাকে তিনটি ইনলাইন যুক্ত করতে হবে। আমি জ্যাঙ্গো-অতিরিক্ত-দৃষ্টিভঙ্গি চেষ্টা করেছি কিন্তু সেই কাজটি করতে পারি নি। আপনি প্রায় 5 টির মতো একই দর্শনের জন্য একাধিক ইনলাইন যোগ করার পরামর্শ দিলে প্রশংসা করবেন All আমি যা অর্জন করতে চাই তা তৈরি করতে একটি একক পৃষ্ঠা Employeeএবং এর ইনলাইনগুলি পছন্দ করে Education, Experience, Others। নীচে কোডটি দেওয়া হল:

মডেল:

class Employee(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employees',
                                null=True, blank=True)
    about = models.TextField()
    street = models.CharField(max_length=200)
    city = models.CharField(max_length=200)
    country = models.CharField(max_length=200)
    cell_phone = models.PositiveIntegerField()
    landline = models.PositiveIntegerField()

    def __str__(self):
        return '{} {}'.format(self.id, self.user)

    def get_absolute_url(self):
        return reverse('bars:create', kwargs={'pk':self.pk})

class Education(models.Model):
    employee = models.ForeignKey('Employee', on_delete=models.CASCADE, related_name='education')
    course_title = models.CharField(max_length=100, null=True, blank=True)
    institute_name = models.CharField(max_length=200, null=True, blank=True)
    start_year = models.DateTimeField(null=True, blank=True)
    end_year = models.DateTimeField(null=True, blank=True)

    def __str__(self):
        return '{} {}'.format(self.employee, self.course_title)

দেখুন:

class EmployeeCreateView(CreateView):
    model = Employee
    template_name = 'bars/crt.html'
    form_class = EmployeeForm
    success_url = None

    def get_context_data(self, **kwargs):
        data = super(EmployeeCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            data['education'] = EducationFormset(self.request.POST)
        else:
            data['education'] = EducationFormset()
        print('This is context data {}'.format(data))
        return data


    def form_valid(self, form):
        context = self.get_context_data()
        education = context['education']
        print('This is Education {}'.format(education))
        with transaction.atomic():
            form.instance.employee.user = self.request.user
            self.object = form.save()
            if education.is_valid():
                education.save(commit=False)
                education.instance = self.object
                education.save()

        return super(EmployeeCreateView, self).form_valid(form)

    def get_success_url(self):
        return reverse_lazy('bars:detail', kwargs={'pk':self.object.pk})

ফর্মগুলি:

class EducationForm(forms.ModelForm):
    class Meta:
        model = Education
        exclude = ()
EducationFormset =inlineformset_factory(
    Employee, Education, form=EducationForm,
    fields=['course_title', 'institute_name'], extra=1,can_delete=True
    )

class EmployeeForm(forms.ModelForm):

    class Meta:
        model = Employee
        exclude = ('user', 'role')

    def __init__(self, *args, **kwargs):
        super(EmployeeForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_tag = True
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-md-3 create-label'
        self.helper.field_class = 'col-md-9'
        self.helper.layout = Layout(
            Div(
                Field('about'),
                Field('street'),
                Field('city'),
                Field('cell_phone'),
                Field('landline'),
                Fieldset('Add Education',
                    Formset('education')),
                HTML("<br>"),
                ButtonHolder(Submit('submit', 'save')),
                )
            )

উদাহরণ অনুসারে কাস্টম লেআউট অবজেক্ট:

from crispy_forms.layout import LayoutObject, TEMPLATE_PACK
from django.shortcuts import render
from django.template.loader import render_to_string

class Formset(LayoutObject):
    template = "bars/formset.html"

    def __init__(self, formset_name_in_context, template=None):
        self.formset_name_in_context = formset_name_in_context
        self.fields = []
        if template:
            self.template = template

    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
        formset = context[self.formset_name_in_context]
        return render_to_string(self.template, {'formset': formset})

Formset.html:

{% load static %}
{% load crispy_forms_tags %}
{% load staticfiles %}

<table>
{{ formset.management_form|crispy }}

    {% for form in formset.forms %}
            <tr class="{% cycle 'row1' 'row2' %} formset_row-{{ formset.prefix }}">
                {% for field in form.visible_fields %}
                <td>
                    {# Include the hidden fields in the form #}
                    {% if forloop.first %}
                        {% for hidden in form.hidden_fields %}
                            {{ hidden }}
                        {% endfor %}
                    {% endif %}
                    {{ field.errors.as_ul }}
                    {{ field|as_crispy_field }}
                </td>
                {% endfor %}
            </tr>
    {% endfor %}

</table>
<br>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js">
</script>
<script src="{% static 'js/jquery.formset.js' %}">
</script>
<script type="text/javascript">
    $('.formset_row-{{ formset.prefix }}').formset({
        addText: 'add another',
        deleteText: 'remove',
        prefix: '{{ formset.prefix }}',
    });
</script>

টার্মিনাল এবং অন্যথায় কোনও ত্রুটি নেই। সাহায্য অনেক প্রশংসা করা হয়।


বিকল্প সমাধানটি হ'ল ফর্ম্যাটটিও হ্যান্ডেল করা উচিত: আমি এটি schinckel.net/2019/05/23/form-and-forset- এ সম্পর্কিত ফর্মसेटটির জন্য ক্যাশেড_প্রোপার্টি ব্যবহার করে করি
ম্যাথু শিনকেল

উত্তর:


0

আপনি বর্তমানে নিজের মধ্যে ফর্মसेटটি সঠিকভাবে প্রক্রিয়া করছেন না CreateViewform_validসেই দৃশ্যে কেবলমাত্র প্যারামেন্ট ফর্মটিই হ্যান্ডেল করা হবে, ফর্মসেটগুলি নয়। আপনার যা করা উচিত তা হ'ল postপদ্ধতিটি ওভাররাইড করে এবং সেখানে আপনাকে ফর্ম এবং এটির সাথে সংযুক্ত যে কোনও ফর্মসেট উভয়ই বৈধ করে তুলতে হবে:

def post(self, request, *args, **kwargs):
    form = self.get_form()
    # Add as many formsets here as you want
    education_formset = EducationFormset(request.POST)
    # Now validate both the form and any formsets
    if form.is_valid() and education_formset.is_valid():
        # Note - we are passing the education_formset to form_valid. If you had more formsets
        # you would pass these as well.
        return self.form_valid(form, education_formset)
    else:
        return self.form_invalid(form)

তারপরে আপনি এটির form_validমতো পরিবর্তন করুন :

def form_valid(self, form, education_formset):
    with transaction.atomic():
        form.instance.employee.user = self.request.user
        self.object = form.save()
        # Now we process the education formset
        educations = education_formset.save(commit=False)
        for education in educations:
            education.instance = self.object
            education.save()
        # If you had more formsets, you would accept additional arguments and
        # process them as with the one above.
    # Don't call the super() method here - you will end up saving the form twice. Instead handle the redirect yourself.
    return HttpResponseRedirect(self.get_success_url())

আপনি বর্তমানে যেভাবে ব্যবহার করছেন সেগুলি get_context_data()সঠিক নয় - এই পদ্ধতিটি সম্পূর্ণ মুছে ফেলুন। এটি কেবলমাত্র একটি টেমপ্লেট রেন্ডার করার জন্য প্রসঙ্গ ডেটা আনতে ব্যবহার করা উচিত। আপনার এটি আপনার form_valid()পদ্ধতি থেকে কল করা উচিত নয় । পরিবর্তে post()উপরে বর্ণিত পদ্ধতি হিসাবে আপনাকে এই পদ্ধতিতে ফর্মसेटটি পাস করতে হবে ।

আমি উপরের নমুনা কোডটিতে কয়েকটি অতিরিক্ত মন্তব্য রেখেছি যা আশা করি এটি আপনাকে খুঁজে বের করতে সহায়তা করবে।


উত্তর দেওয়ার আগে দয়া করে স্থানীয়ভাবে একটি উদাহরণ তৈরি করুন। আমি আপনার টুকরা চেষ্টা করেছি কিন্তু কাজ করছে না।
শাজিয়া নুসরত

1
@ শাজিয়া নুসরত দুঃখিত, আপনার জন্য যা কাজ করছে না তা চেষ্টা করার এবং কাজ করার আমার কাছে সময় নেই, বিশেষ করে যদি আপনি না বলে থাকেন যে আপনি যা চেষ্টা করেছেন এবং কোনটি কার্যকর হয়নি ("এটি কাজ করছে না" এটি নয়) কি কাজ করেনি তার পর্যাপ্ত বিবরণ)। আমি বিশ্বাস করি যে আপনার বর্তমান প্রয়োগের সাথে আপনার কী পরিবর্তন করতে হবে তা সনাক্ত করতে আমার উত্তরের যথেষ্ট রয়েছে answer যদি তা না হয় তবে আসুন আশা করি অন্য কেউ আপনাকে আরও বিস্তৃত উত্তর দিতে সক্ষম হবেন।
solarissmoke

আমি পরীক্ষার জন্য কোডটিতে এটি চেষ্টা করেছিলাম এবং এটি সমস্যা নিয়ে চলেছিল। এ কারণেই আমি আপনাকে বিনীতভাবে অনুরোধ করছি যাতে আপনি স্থানীয়ভাবে এটি চেষ্টা করে দেখুন যাতে আপনি আমাকে আরও ভালভাবে পরিচালনা করতে পারেন। আপনি আমাকে কিছুটা সময় দেওয়ার জন্য আমি কৃতজ্ঞ। কিন্তু কাজ হচ্ছে না।
শাজিয়া নুসরত

0

হতে পারে আপনি প্যাকেজটি django-extra-viewsদেখতে চান CreateWithInlinesView, দর্শনটি সরবরাহ করে , জাদুকরী আপনাকে জ্যাঙ্গো-অ্যাডমিন ইনলাইনসের মতো নেস্টেড ইনলাইনগুলির সাথে ফর্ম তৈরি করতে দেয়।

আপনার ক্ষেত্রে এটি এমন কিছু হবে:

views.py

class EducationInline(InlineFormSetFactory):
    model = Education
    fields = ['course_title', 'institute_name']


class EmployeeCreateView(CreateWithInlinesView):
    model = Employee
    inlines = [EducationInline,]
    fields = ['about', 'street', 'city', 'cell_phone', 'landline']
    template_name = 'bars/crt.html'

crt.html

<form method="post">
  ...
  {{ form }}
  <table>
  {% for formset in inlines %}
    {{ formset.management_form }}
      {% for inline_form in formset %}
        <tr class="{% cycle 'row1' 'row2' %} formset_row-{{ formset.prefix }}">
          {{ inline_form }}
        </tr>
      {% endfor %}
  {% endfor %}
  </table>
  ...
  <input type="submit" value="Submit" />
</form>

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js">
</script>
<script src="{% static 'js/jquery.formset.js' %}">
</script>
<script type="text/javascript">
    {% for formset in inlines %}
      $('.formset_row-{{ formset.prefix }}').formset({
          addText: 'add another',
          deleteText: 'remove',
          prefix: '{{ formset.prefix }}',
      });
    {% endfor %}
</script>

EmployeeCreateViewজ্যাঙ্গো-অ্যাডমিনের মতো এই ভিউটি আপনার জন্য ফর্মগুলি প্রক্রিয়াজাত করবে। এই বিন্দু থেকে আপনি ফর্মগুলিতে যে স্টাইলটি চান তা প্রয়োগ করতে পারেন।

আমি আপনাকে আরও তথ্যের জন্য ডকুমেন্টেশন পরিদর্শন সুপারিশ

সম্পাদিত: আমি যুক্ত করেছি management_form এবং জেএস বোতামগুলি যোগ / অপসারণ করতে।


আমি এটি ইতিমধ্যে চেষ্টা করেছি কিন্তু এটি আমাকে একাধিক ইনলাইনগুলির জন্য বোতাম যুক্ত / মুছতে দেয় না। এটি কেবল জেএস বোতামগুলির সাথে একটি ইনলাইন সমর্থন করে। আমি ইতিমধ্যে চেষ্টা করেছি।
শাজিয়া নুসরত

1
এটি এটি সমর্থন করে, আপনার management_formপ্রত্যেকটির জন্য যোগ করতে হবেformset
জন

0

আপনি বলেছিলেন যে এখানে একটি ত্রুটি রয়েছে তবে আপনি এটি আপনার প্রশ্নে প্রদর্শন করছেন না। ত্রুটি (এবং পুরো ট্রেসব্যাক) আপনি যে কোনও কিছু লিখেছেন (ফর্ম.পি এবং ভিউপিপি থেকে থাকতে পারে) এর চেয়ে গুরুত্বপূর্ণ is

একই ক্রেডিটভিউতে ফর্মসেটগুলি এবং একাধিক ফর্ম ব্যবহার করার কারণে আপনার কেসটি কিছুটা জটিল। ইন্টারনেটে অনেকগুলি (বা খুব ভাল নয়) উদাহরণ নেই। জঞ্জো কোডটি খনন না করা পর্যন্ত কীভাবে ইনলাইন ফর্মসেটগুলি কাজ করছে আপনার সমস্যা হবে।

ঠিক আছে বিন্দু। আপনার সমস্যাটি হ'ল ফর্মসেটগুলি আপনার মূল ফর্মের মতো একই উদাহরণ দিয়ে আরম্ভ করা হয়নি। এবং যখন আপনার আমিন ফর্মটি ডাটাবেসে ডেটা সংরক্ষণ করে ফর্মসেটের উদাহরণটি পরিবর্তন করা হয় না এবং শেষে আপনার কাছে বিদেশী কী হিসাবে রাখার জন্য প্রধান অবজেক্টের আইডি থাকে না। আরম্ভের পরে কোনও ফর্মের অ্যাট্রিবিউটের উদাহরণ বৈশিষ্ট্য পরিবর্তন করা ভাল ধারণা নয়।

সাধারণ ফর্মগুলিতে আপনি যদি এটি_অডিয়ালের পরে ছানতে থাকেন তবে আপনার অনাকাঙ্ক্ষিত ফলাফল হবে। ফর্মসেটের জন্য উদাহরণস্বরূপ এন্টিবিউটরিটি পরিবর্তন করার পরেও প্রত্যক্ষভাবে থিম নহিগ হবে না, ফর্মসেটে ফর্মগুলি ইতিমধ্যে কিছু উদাহরণ দিয়ে শুরু করা হয়েছে, এবং পরে এটি পরিবর্তন করা কোনও উপকারে আসবে না। সুসংবাদটি হ'ল ফর্মसेटটি আরম্ভ করার পরে আপনি উদাহরণের বৈশিষ্ট্যগুলি পরিবর্তন করতে পারেন, কারণ ফর্মসেট শুরু হওয়ার পরে সমস্ত ফর্মের উদাহরণ বৈশিষ্ট্যগুলি একই অবজেক্টে নির্দেশ করবে।

আপনার দুটি বিকল্প রয়েছে:

ফর্মসেটটি উদাহরণ বৈশিষ্ট্য নির্ধারণের পরিবর্তে, কেবলমাত্র inst.pk সেট করুন। (এটি কেবল অনুমান করার আগে আমি এটি কখনই করি নি তবে আমি মনে করি এটি কাজ করা উচিত The সমস্যাটি হ্যাকের মতো দেখাবে)। এমন একটি ফর্ম তৈরি করুন যা একবারে সমস্ত ফর্ম / ফর্মসেটগুলি আরম্ভ করবে। যখন এটি_অডিয়াল () পদ্ধতি বলা হয় তখন সমস্ত ফোমারকে বৈধতা দেওয়া উচিত। যখন সেভ () পদ্ধতিটি বলা হয় তখন সমস্ত ফর্মগুলি সংরক্ষণ করতে হবে। তারপরে আপনাকে সেই ফর্ম শ্রেণিতে আপনার ক্রিয়েটভিউর ফর্ম_ক্লাস বৈশিষ্ট্যটি সেট করতে হবে। কেবলমাত্র জটিল অংশটি হ'ল আপনার মূল ফর্মটি আরম্ভ করার পরে আপনার নিজের প্রথম ফর্মের উদাহরণ দিয়ে অন্যগুলি (সূত্রগুলি) আরম্ভ করতে হবে। এছাড়াও টেমপ্লেটে অ্যাক্সেস পেতে আপনার ফর্মগুলির বৈশিষ্ট্য হিসাবে ফর্মগুলি / ফর্মসেটগুলি সেট করতে হবে। আমি এটি সম্পর্কিত সমস্ত অবজেক্টের সাথে যখন কোনও অবজেক্ট তৈরি করা দরকার তখন আমি দ্বিতীয় পদ্ধতির ব্যবহার করছি using

কিছু ডেটা দিয়ে সূচনা (এই ক্ষেত্রে পোস্টের ডেটা) is_ માન્ય () এর সাথে বৈধতার জন্য যাচাই করা হয়েছে যখন এটি বৈধ হবে তখন সেভ () দিয়ে সংরক্ষণ করা যায়। আপনি ফর্ম ইন্টারফেস সংরক্ষণ করেন এবং আপনি যদি আপনার ফর্মটি সঠিকভাবে তৈরি করেন তবে আপনি এটি কেবল তৈরির জন্যই ব্যবহার করতে পারবেন না তবে তাদের সম্পর্কিত অবজেক্টগুলির সাথে একসাথে অবজেক্টগুলি আপডেট করার জন্য এবং ভিউগুলি খুব সহজ হবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.