请告诉我如何保存一个表单集,其中有两个模型与manytomanyfield关系相关,原来当页面打开时显示两个表单,填写并点击“添加”按钮后,“phone”和“client_name”字段被清除,表单没有发送。在视图类OrderView(OrderView)中,检查client_formset.is_valid()返回False。
代码如下:
models.py
from django.db import models
from django.contrib.auth.models import User
class Client(models.Model):
phone = models.CharField(max_length=20, verbose_name='Телефон')
client_name = models.CharField(max_length=100, verbose_name='ФИО клиента')
def __str__(self):
return '%s %s' % (self.phone, self.client_name)
class Meta:
verbose_name = 'Клиент'
verbose_name_plural = 'Клиенты'
class Order(models.Model):
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name='Принял', blank=True)
date_of_creation = models.DateTimeField(auto_now=True, verbose_name='Дата создания')
execution_date = models.DateField(verbose_name='Дата исполнения')
address = models.CharField(max_length=200, verbose_name='Адрес')
service = models.CharField(max_length=100, verbose_name='Услуга')
master = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='master', null=True, verbose_name='Мастер', blank=True)
client = models.ManyToManyField(Client, verbose_name='Клиент', blank=True)
def __str__(self):
return '%s %s %s' % (self.execution_date, self.address, self.service)
class Meta:
verbose_name = 'Заявка'
verbose_name_plural = 'Заявки'
字符串
forms.py
from django import forms
# from .models import Orders, Person, Phone
from .models import Order, Client
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User
from django.forms import modelformset_factory
class UserFullnameChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.get_full_name()
class OrderForm(forms.ModelForm):
master = UserFullnameChoiceField(queryset=User.objects.all(), label='Мастер')
class Meta:
model = Order
fields = ('execution_date', 'address', 'service', 'master')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['master'].empty_label = '-Выберите мастера-'
for field in self.fields:
self.fields[field].widget.attrs['class'] = 'form-control'
# Form for clients
class ClientForm(forms.ModelForm):
phone = forms.CharField(max_length=20, label='Телефон', required=True)
client_name = forms.CharField(max_length=100, label='ФИО клиента', required=True)
class Meta:
model = Client
fields = ['phone', 'client_name']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs['class'] = 'form-control'
# Formset for clients
ClientFormSet = modelformset_factory(Client, form=ClientForm, extra=1)
型
views.py
from django.shortcuts import render, redirect
from .models import Order, Client
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from .forms import OrderForm, AuthUserForm, RegisterUserForm, ClientForm
from django.urls import reverse, reverse_lazy
from django.contrib import messages
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.forms import modelformset_factory
class OrderCreateView(CreateView):
model = Order
form_class = OrderForm
template_name = 'create.html'
success_url = reverse_lazy('data_base')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
ClientFormSet = modelformset_factory(Client, form=ClientForm, extra=1)
context['client_formset'] = ClientFormSet(queryset=Client.objects.none())
return context
def form_valid(self, form):
context = self.get_context_data()
client_formset = context['client_formset']
if form.is_valid() and client_formset.is_valid():
self.object = form.save(commit=False)
for client_form in client_formset:
if client_form.cleaned_data:
client = client_form.save(commit=False)
client.order = self.object
client.save()
form.save()
return super().form_valid(form)
else:
return self.render_to_response(self.get_context_data(form=form, client_formset=client_formset))
型
create.html
{% extends 'base.html' %}
{% block title %}
Создать заявку
{% endblock %}
{% block content %}
<h1>Creating an application</h1>
{% if success %}
<p class="text-success">Заявка добавлена</p>
{% elif success == False %}
<p class="text-danger">Ошибка</p>
{% endif %}
<form id="add_form" method="post">
{% csrf_token %}
{{ form }}
<div id="client-fields">
{% for form in client_formset %}
<div class="client-form">
<div class="form-group">
<label for="{{ form.client_name.id_for_label }}">ФИО клиента</label>
{{ form.client_name }}
</div>
<div class="form-group">
<label for="{{ form.phone.id_for_label }}">Телефон</label>
{{ form.phone }}
</div>
<button type="button" class="remove-client">Delete</button>
</div>
{% endfor %}
</div>
<button type="button" id="add-client-field">Add client</button>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
<button form="add_form" type="submit" class="btn btn-primary">Add</button>
</div>
</form>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
$('#add-client-field').click(function() {
var clientField = $('#client-fields .client-form:first').clone(true);
// Clear the field values in the new field
clientField.find('input').val('');
clientField.find('input[name*=client_name]').attr('name', 'client_name_' + $('#client-fields .client-form').length);
clientField.find('input[name*=phone]').attr('name', 'phone_' + $('#client-fields .client-form').length);
clientField.insertAfter('#client-fields .client-form:last');
});
$(document).on('click', '.remove-client', function() {
if ($('#client-fields .client-form').length > 1) {
$(this).closest('.client-form').remove();
}
});
});
</script>
{% endblock %}
型
这一切都是为了在创建应用程序时,您可以添加几个具有电话号码的客户端
1条答案
按热度按时间dwthyt8l1#
你不能创建一个关系到一个还没有保存的对象。所以你必须在处理
client_form
之前保存self.object
。假设您处于事务中,如果出现任何错误(引发未处理的异常),对象将被取消保存(或者更确切地说,数据库事务将不会被提交)
试试这个
字符串