多对多关系保存在一种表单上,而不是另一种表单上

问题描述 投票:0回答:1

我很茫然, 我有一些代码可以使用 FilteredSelectMultiple 小部件在多对多关系上保存模型表单。 它适用于 4 种形式中的 2 种。但我不明白为什么它在最后两个不起作用。 有什么帮助吗?

这是正在运行的两个之一的代码:

forms.py:

class SubDomainForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.required = False

    domains = forms.ModelMultipleChoiceField(queryset=Domain.objects.all(), label=('domains'), widget=FilteredSelectMultiple(('domains'), False, ))
    subdomains = forms.ModelMultipleChoiceField(queryset=SubDomain.objects.all(), label=('subdomains'), widget=FilteredSelectMultiple(('subdomains'), False, ))
    
    class Media:
        extend = False
        css = {
            'all': [
                '/static/admin/css/widgets.css'
            ]
        }
        js = (
            '/static/assets/admin/js/django_global.js',
            '/static/assets/admin/js/jquery.init.js',
            '/static/assets/admin/js/core.js',
            '/static/assets/admin/js/prepopulate_init.js',
            '/static/assets/admin/js/prepopulate.js',
            '/static/assets/admin/js/SelectBox.js',
            '/static/assets/admin/js/SelectFilter2.js',
            '/static/assets/admin/js/admin/RelatedObjectLookups.js',
        )  

    class Meta:
        model = SubDomain
        fields = ('domains', 'subdomains', 'name', 'description')
        widgets = {'description': CKEditorWidget(),}

models.py:

class SubDomain(models.Model):
    domains = models.ManyToManyField(Domain, verbose_name='Link to Domain', blank=True)
    subdomains = models.ManyToManyField('self', verbose_name='Link to other SubDomain', blank=True)
    name = models.CharField(max_length=50)
    description = RichTextField()

    def __str__(self):
        return f"{self.name}"

    class Meta:
        verbose_name_plural = '   SubDomain'

HTML:

<!--- api\formfiller\templates\subdomain_form.html -->
{% load static %}
{% block head %}
<head>
    {{ form.media }}
    {{ form.media }}
    <style>
        .ck.ck-editor__main > .ck-editor__editable:not(.ck-focused) {
            width: 800px;
            height: 300px;
        }
        .ck-rounded-corners .ck.ck-editor__main > .ck-editor__editable, .ck.ck-editor__main > .ck-editor__editable.ck-rounded-corner {
            width: 800px;
            height: 300px;
        }
        .cke_top {
            padding: 0px 0px 0px;
        }
        .fieldWrapper { 
            margin-left: 15px;
        }
    </style>

</head>
{% endblock %}

<div class="fieldWrapper related-widget-wrapper">
    <form method="post" action="{% url 'submit_form' %}" id="submit-form">
        <legend>Create SubDomain</legend>      
        {% csrf_token %}

        <table>
            {{ form.as_table }}
        </table>
        <!-- Hidden input fields for name, description, and selected SuBdomains -->
        <input type="hidden" name="form_type" value="subdomain">      
        <input type="submit" value="Submit">
        <script>
                document.addEventListener('DOMContentLoaded', function () {
                    ClassicEditor
                        .create(document.querySelector('#id_description'))
                        .then(editor => {
                            console.log(editor);
                        })
                        .catch(error => {
                            console.error(error);
                        });

                    // Initialize the SelectFilter widget
                    SelectFilter.init('id_domains', "Domains", false); // Ensure 'id_domains' matches your field ID
                    SelectFilter.init('id_subdomains', "SubDomains", false); // Ensure 'id_subdomains' matches your field ID

                    document.getElementById('submit-form').addEventListener('submit', function (e) {
                        e.preventDefault();  // Prevent the form from submitting traditionally

                        // Use JavaScript Fetch or jQuery AJAX to submit the form
                        fetch("{% url 'submit_form' %}", {
                            method: 'POST',
                            body: new FormData(this),
                            headers: {
                                'X-Requested-With': 'XMLHttpRequest',  // Indicate an AJAX request
                                'X-CSRFToken': '{{ csrf_token }}',  // Include the CSRF token
                            },
                        })
                        .then(response => response.json())
                        .then(data => {
                            if (data.success) {
                                // Show a Toastr success notification
                                toastr.success(data.message);
                                document.getElementById('submit-form').reset();
                                // You can also reset the form or perform other actions here
                                // Example: document.getElementById('submit-form').reset();

                                // Wait for one second before reloading the form
                                setTimeout(function () {
                                    location.reload();
                                }, 500);
                            } else {
                                // Show a Toastr error notification
                                toastr.error(data.message);
                            }
                        })
                        .catch(error => {
                            // Handle AJAX error
                            console.error(error);
                        });
                    });
                });

            </script>
    </form>
</div>
<footer>
    <style>
    .selector h2 {
        margin: 0;
        padding: 8px;
        font-weight: 400;
        font-size: 15px;
        text-align: left;
        background: #888;
        color: white;
        }
    </style>
</footer>

这是其中一个不起作用的代码:

forms.py:

class SkillForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.required = False

    subdomains = forms.ModelMultipleChoiceField(queryset=SubDomain.objects.all(), label=('subdomains'), widget=FilteredSelectMultiple(('subdomains'), False, ))
    skills = forms.ModelMultipleChoiceField(queryset=Skill.objects.all(), label=('skills'), widget=FilteredSelectMultiple(('skills'), False, ))

    class Media:
        extend = False
        css = {
            'all': [
                '/static/admin/css/widgets.css'
            ]
        }
        js = (
            '/static/assets/admin/js/django_global.js',
            '/static/assets/admin/js/jquery.init.js',
            '/static/assets/admin/js/core.js',
            '/static/assets/admin/js/prepopulate_init.js',
            '/static/assets/admin/js/prepopulate.js',
            '/static/assets/admin/js/SelectBox.js',
            '/static/assets/admin/js/SelectFilter2.js',
            '/static/assets/admin/js/admin/RelatedObjectLookups.js',
        )  

    class Meta:
        model = Skill
        fields = ('subdomains', 'skills', 'name', 'description')
        widgets = {'description': CKEditorWidget(),}

models.py:

class Skill(models.Model):
    subdomain = models.ManyToManyField(SubDomain, verbose_name='Link to SubDomain', blank=True)
    skill = models.ManyToManyField('self', verbose_name='Link to other skill', blank=True)
    name = models.CharField(max_length=50)
    description = RichTextField()

    def __str__(self):
        return f"{self.name}"

    class Meta:
        verbose_name_plural = '  Skill'

HTML:

<!--- api\formfiller\templates\skill_form.html -->
{% load static %}
{% block head %}
<head>
    {{ form.media }}
    {{ form.media }}
    <style>
        .ck.ck-editor__main > .ck-editor__editable:not(.ck-focused) {
            width: 800px;
            height: 300px;
        }
        .ck-rounded-corners .ck.ck-editor__main > .ck-editor__editable, .ck.ck-editor__main > .ck-editor__editable.ck-rounded-corner {
            width: 800px;
            height: 300px;
        }
        .cke_top {
            padding: 0px 0px 0px;
        }
        .fieldWrapper { 
            margin-left: 15px;
        }
    </style>

</head>
{% endblock %}

<div class="fieldWrapper related-widget-wrapper">
    <form method="post" action="{% url 'submit_form' %}" id="submit-form">
        <legend>Create Skill</legend>      
        {% csrf_token %}

        <table>
            {{ form.as_table }}
        </table>
        <!-- Hidden input fields for name, description, and selected Skills -->
        <input type="hidden" name="form_type" value="skill">      
        <input type="submit" value="Submit">
        <script>
                document.addEventListener('DOMContentLoaded', function () {
                    ClassicEditor
                        .create(document.querySelector('#id_description'))
                        .then(editor => {
                            console.log(editor);
                        })
                        .catch(error => {
                            console.error(error);
                        });

                    // Initialize the SelectFilter widget
                    SelectFilter.init('id_subdomains', "SubDomains", false); // Ensure 'id_domains' matches your field ID
                    SelectFilter.init('id_skills', "Skills", false); // Ensure 'id_subdomains' matches your field ID

                    document.getElementById('submit-form').addEventListener('submit', function (e) {
                        e.preventDefault();  // Prevent the form from submitting traditionally

                        // Use JavaScript Fetch or jQuery AJAX to submit the form
                        fetch("{% url 'submit_form' %}", {
                            method: 'POST',
                            body: new FormData(this),
                            headers: {
                                'X-Requested-With': 'XMLHttpRequest',  // Indicate an AJAX request
                                'X-CSRFToken': '{{ csrf_token }}',  // Include the CSRF token
                            },
                        })
                        .then(response => response.json())
                        .then(data => {
                            if (data.success) {
                                // Show a Toastr success notification
                                toastr.success(data.message);
                                document.getElementById('submit-form').reset();
                                // You can also reset the form or perform other actions here
                                // Example: document.getElementById('submit-form').reset();

                                // Wait for one second before reloading the form
                                setTimeout(function () {
                                    location.reload();
                                }, 500);
                            } else {
                                // Show a Toastr error notification
                                toastr.error(data.message);
                            }
                        })
                        .catch(error => {
                            // Handle AJAX error
                            console.error(error);
                        });
                    });
                });

            </script>
    </form>
</div>
<footer>
    <style>
    .selector h2 {
        margin: 0;
        padding: 8px;
        font-weight: 400;
        font-size: 15px;
        text-align: left;
        background: #888;
        color: white;
        }
    </style>
</footer>

这是views.py:


#handle form submission
def submit_form(request):
    if request.method == 'POST':
        form_type = request.POST.get('form_type')
        print(f"Form type: {form_type}")

        # Print the entire POST data dictionary
        print(request.POST)

        # Define a dictionary to map form types to form classes
        form_type_mapping = {
            'domain': (DomainForm, Domain),
            'subdomain': (SubDomainForm, SubDomain),
            'skill': (SkillForm, Skill),
            'tool': (ToolForm, Tool),
        }

        # Check if the form_type is valid
        if form_type in form_type_mapping:
            FormClass, model_class = form_type_mapping[form_type]
            form = FormClass(request.POST, request.FILES)

            if form.is_valid():
                # Process and save the form data to the corresponding model
                instance = form.save(commit=False)
                instance.name = form.cleaned_data['name']
                instance.description = form.cleaned_data['description']
                instance.save()

                # Save many-to-many relationships
                form.save_m2m()

                # Return a JSON response indicating success
                return JsonResponse({'success': True, 'message': 'Form submitted successfully'})
        else:
            return JsonResponse({'success': False, 'message': 'Invalid form_type'})

    # Handle other cases and errors
    return JsonResponse({'success': False, 'message': 'Invalid request method'})

我尝试了多种方法来保存表单,但它只保存了其中的两种。 我正在正确接收帖子数据,如控制台中的这些打印所示:

工作:

Form type: subdomain
<QueryDict: {'csrfmiddlewaretoken': ['TcxcKoJ7PHIkKQC9PpfLJH9kIx5cMvQjzLMHBhun3s5Wb9j3wntJViiuBi68haqC'], 'domains': ['1'], 'subdomains': ['1'], 'name': ['Test SubDomain name'], 'description': ['<p>Test SubDomain description</p>'], 'form_type': ['subdomain']}>

不工作:

Form type: skill
<QueryDict: {'csrfmiddlewaretoken': ['9vFGK25Y4x86O8iSc40lxGl7AqvxIHieP4UbBVQeiivIfrZMT2ejJhuhtbwtdmSx'], 'subdomains': ['1'], 'skills': ['1'], 'name': ['test skill name'], 'description': ['<p>test skill description</p>'], 'form_type': ['skill']}>
javascript html django forms django-forms
1个回答
0
投票

已解决:

我的模型中缺少 S。

    subdomain**s** = models.ManyToManyField(SubDomain, verbose_name='Link to SubDomain', blank=True)
skill**s** = models.ManyToManyField('self', verbose_name='Link to other skill', blank=True)
© www.soinside.com 2019 - 2024. All rights reserved.