我在将表单保存到数据库时遇到问题。我尝试过的所有方法都不起作用,我真的不知道还能做什么。
我在 Django 中创建了一个手动表单,保存时绝对没有错误,一切正常,没有任何错误,我什至被重定向到成功页面,但数据库中什么也没有。
# models.py
class Lead(Model):
lead_status = CharField(choices=STATUS, default='Activă', verbose_name='Status cerere')
property_type = CharField(choices=TIP_PROPRIETATE, default='Apartament', verbose_name='Tip cerere')
transaction_type = CharField(choices=TIP_TRANZACTIE, verbose_name='Tip tranzacție')
contact = ForeignKey(Contact, on_delete=SET_NULL, null=True, verbose_name='Contact asociat')
county = CharField(choices=JUDETE, verbose_name='Județ')
city = CharField(max_length=30, verbose_name='Localitate')
zone = CharField(max_length=30, null=True, blank=True, verbose_name='Zonă')
street = CharField(max_length=40, null=True, blank=True, verbose_name='Stradă')
budget = IntegerField(null=True, blank=True, verbose_name='Buget alocat')
payment_method = CharField(choices=MODALITATE_PLATA, null=True, blank=True, verbose_name='Modalitate plată', )
urgency = CharField(choices=URGENTA, default='Normal', verbose_name='Urgență')
other_details = TextField(max_length=2000, null=True, blank=True, verbose_name='Alte detalii')
labels = CharField(choices=ETICHETA, null=True, blank=True, verbose_name='Etichete')
notes = TextField(max_length=2000, null=True, blank=True, verbose_name='Notițe proprii')
created_at = DateTimeField(auto_now_add=True, verbose_name='Data introducerii')
updated_at = DateTimeField(auto_now=True, verbose_name='Data ultimei actualizări')
deadline_date = DateField(null=True, blank=True, verbose_name='Data limită')
deadline_time = TimeField(null=True, blank=True, verbose_name='Ora limită')
class Meta:
abstract = True
def __str__(self):
return f'{self.contact}'
class ApartmentLead(Lead):
apartment_type = CharField(choices=TIP_APARTAMENT, verbose_name='Tip apartament')
destination = CharField(choices=DESTINATIE_AP, verbose_name='Destinație')
rooms_number = IntegerField(null=True, blank=True, verbose_name='Număr camere')
nr_bedrooms = IntegerField(null=True, blank=True, verbose_name='Număr dormitoare')
nr_bathrooms = IntegerField(null=True, blank=True, verbose_name='Număr băi')
bathroom_window = BooleanField(default=False, verbose_name='Geam la baie')
floor = CharField(choices=ETAJ_AP, null=True, blank=True, verbose_name='Etaj')
excluded_ground_floor = BooleanField(default=False, verbose_name='Exclus parter')
excluded_top_floor = BooleanField(default=False, verbose_name='Exclus ultimul etaj')
nr_floors = IntegerField(null=True, blank=True, verbose_name='Număr etaje')
minimal_surface = DecimalField(max_digits=5, decimal_places=2, null=True, blank=True, verbose_name='Suprafață minimă (mp)')
construction_status = CharField(choices=STADIU_CONSTRUCTIE, null=True, blank=True, verbose_name='Stadiu construcție')
furniture = CharField(choices=MOBILIER, null=True, blank=True, verbose_name='Mobilier')
comfort = CharField(choices=CONFORT, null=True, blank=True, verbose_name='Confort')
ap_compart = CharField(choices=COMPARTIMENTARE_AP, null=True, blank=True, verbose_name='Compartimentare')
orientation = CharField(choices=ORIENTARE, null=True, blank=True, verbose_name='Orientare')
interior_finishes = CharField(choices=FINISAJE, null=True, blank=True, verbose_name='Stare interior')
construction_year = IntegerField(null=True, blank=True, verbose_name='Anul construcției')
basement = BooleanField(default=False, verbose_name='Subsol')
semi_basement = BooleanField(default=False, verbose_name='Demisol')
technical_floor = BooleanField(default=False, verbose_name='Etaj tehnic')
loft = BooleanField(default=False, verbose_name='Mansardă')
attic = BooleanField(default=False, verbose_name='Pod')
elevator = BooleanField(default=False, verbose_name='Lift')
created_by = ForeignKey(User, on_delete=SET_NULL, null=True, blank=True, related_name='my_apartment_key', verbose_name='Agent asociat')
assigned_listings = ForeignKey(Apartment, on_delete=SET_NULL, null=True, blank=True,
related_name='assigned_apartment_key', verbose_name='Proprietăți asociate')
def __str__(self):
return f'{self.apartment_type} - {self.created_by}'
# forms.py
class LeadCreateForm(ModelForm):
class Meta:
model = Lead
fields = '__all__'
widgets = {
'status': Select(attrs={'class': 'form-control'}),
'property_type': Select(attrs={'class': 'form-control'}),
'transaction_type': Select(attrs={'class': 'form-control'}),
'contact': Select(attrs={'class': 'form-control'}),
'county': TextInput(attrs={'class': 'form-control'}),
'city': TextInput(attrs={'class': 'form-control'}),
'zone': TextInput(attrs={'class': 'form-control'}),
'street': TextInput(attrs={'class': 'form-control'}),
'budget': TextInput(attrs={'class': 'form-control'}),
'payment_method': Select(attrs={'class': 'form-control'}),
'urgency': Select(attrs={'class': 'form-control'}),
'other_details': Textarea(attrs={'class': 'form-control', 'rows': '3'}),
'labels': Select(attrs={'class': 'form-control'}),
'notes': Textarea(attrs={'class': 'form-control', 'rows': '3'}),
'created_at': DateInput(attrs={'class': 'form-control'}),
'updated_at': DateInput(attrs={'class': 'form-control'}),
'deadline_date': DateInput(attrs={'type': 'date'}),
'deadline_time': TimeInput(attrs={'type': 'time', 'step': '600'})
}
class ApartmentLeadCreateForm(LeadCreateForm):
class Meta:
model = ApartmentLead
fields = '__all__'
widgets = {
'apartment_type': SelectMultiple(attrs={'class': 'form-control'}),
'destination': Select(attrs={'class': 'form-control'}),
'rooms_number': NumberInput(attrs={'class': 'form-control'}),
'nr_bedrooms': NumberInput(attrs={'class': 'form-control'}),
'nr_bathrooms': NumberInput(attrs={'class': 'form-control'}),
'bathroom_window': CheckboxInput(attrs={'class': 'form-check-input'}),
'floor': SelectMultiple(attrs={'class': 'form-control'}),
'excluded_ground_floor': CheckboxInput(attrs={'class': 'form-check-input'}),
'excluding_top_floor': CheckboxInput(attrs={'class': 'form-check-input'}),
'nr_floors': NumberInput(attrs={'class': 'form-control'}),
'minimal_surface': NumberInput(attrs={'class': 'form-control'}),
'construction_status': SelectMultiple(attrs={'class': 'form-control'}),
'furniture': SelectMultiple(attrs={'class': 'form-control'}),
'comfort': SelectMultiple(attrs={'class': 'form-control'}),
'ap_compart': SelectMultiple(attrs={'class': 'form-control'}),
'orientation': SelectMultiple(attrs={'class': 'form-control'}),
'interior_finishes': SelectMultiple(attrs={'class': 'form-control'}),
'construction_year': NumberInput(attrs={'class': 'form-control'}),
'basement': CheckboxInput(attrs={'class': 'form-check-input'}),
'semi_basement': CheckboxInput(attrs={'class': 'form-check-input'}),
'technical_floor': CheckboxInput(attrs={'class': 'form-check-input'}),
'loft': CheckboxInput(attrs={'class': 'form-check-input'}),
'attic': CheckboxInput(attrs={'class': 'form-check-input'}),
'elevator': CheckboxInput(attrs={'class': 'form-check-input'}),
'assigned_listings': TextInput(attrs={'class': 'form-control'}),
}
def clean(self):
cleaned_data = super().clean()
rooms_number = cleaned_data.get('rooms_number')
bedrooms_number = cleaned_data.get('nr_bedrooms')
if bedrooms_number is not None and rooms_number is not None and bedrooms_number > rooms_number:
raise ValidationError('Numărul de dormitoare nu poate fi mai mare decât numărul total de camere.')
floor = cleaned_data.get('floor')
nr_floors = cleaned_data.get('nr_floors')
if floor is not None and nr_floors is not None and floor > nr_floors:
raise ValidationError('Numărul etajului apartamentului nu poate fi mai mare decât numărul total de etaje.')
return cleaned_data
# urls.py
app_name = 'leads'
urlpatterns = [
path('add-apartment-lead', ApartmentLeadCreateView.as_view(), name='add_apartment_lead'),
]
# views.py
class ApartmentLeadCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
model = ApartmentLead
form_class = ApartmentLeadCreateForm
template_name = 'leads/apartments/add_apartment_lead.html'
success_url = reverse_lazy('leads:lead_added')
permission_required = 'leads.add_apartmentlead'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
stored_contact = self.request.session.get('storedContactId')
stored_type = self.request.session.get('storedType')
context['storedContactId'] = stored_contact
context['storedType'] = stored_type
return context
def form_valid(self, form):
form.instance.created_at = timezone.now()
form.instance.updated_at = timezone.now()
form.instance.created_by = self.request.user
try:
response = super().form_valid(form)
return response
except Exception as e:
print(f"Eroare în timpul salvării datelor: {e}")
return HttpResponseRedirect(self.get_success_url())
# HTML & JavaScript
{% extends 'partials/base.html' %}
{% load static %}
{% block title %} Cerere nouă | Apartament {% endblock title %}
{% block content %}
{% block pagetitle %}
{% include "partials/page_title.html" with pagetitle="Cereri" title="Cerere nouă | Apartament" %}
{% endblock pagetitle %}
{% if user.is_authenticated %}
{% if perms.leads.add_apartmentlead %}
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<form id="add_lead_form" method="post" enctype="multipart/form-data" class="row"
action="{% url 'leads:add_apartment_lead' %}">
{% csrf_token %}
<div class="col-lg-3 col-md-6 col-sm-6">
<div class="card">
<div class="card-body">
<div id="contactInfo">
<h5><span id="firstName"></span> <span id="lastName"></span></h5>
<div id="phoneNumber"></div>
<div id="email"></div>
</div>
<input id="contact" name="contact" type="hidden" value="{{ storedContactId }}"
required>
<hr class="border-secondary-subtle">
<div class="col-lg-12 mb-3">
<label for="property_type" class="form-label">Tip cerere <span
class="text-danger">*</span></label>
<input id="property_type" class="form-control text-muted"
name="property_type" value="{{ storedType }}" readonly required>
</div>
<div class="col-lg-12 mb-3">
<label for="apartment_type" class="form-label">
Tip apartament <span class="text-danger">*</span></label>
<select id="apartment_type" class="form-select" name="apartment_type"
required>
{% for value, label in form.fields.apartment_type.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="col-lg-12 mb-3">
<label for="transaction_type" class="form-label">Tip tranzacție <span
class="text-danger">*</span></label>
<select id="transaction_type" class="form-select" name="transaction_type"
required>
{% for value, label in form.fields.transaction_type.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="col-lg-12">
<label for="lead_status" class="form-label">Status cerere <span
class="text-danger">*</span></label>
<select id="lead_status" class="form-select" name="lead_status" required>
{% for value, label in form.fields.lead_status.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<hr class="border-secondary-subtle">
<div class="col-lg-12 mb-3">
<label for="county" class="form-label">Județ <span
class="text-danger">*</span></label>
<select id="county" class="form-control" name="county" data-choices
required>
{% for value, label in form.fields.county.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="col-lg-12 mb-3">
<label for="city" class="form-label">Localitate <span
class="text-danger">*</span></label>
<input id="city" class="form-control" name="city" type="text" required>
</div>
<div class="col-lg-12 mb-3">
<label for="zone" class="form-label">Zonă</label>
<input id="zone" class="form-control" name="zone" type="text">
</div>
<div class="col-lg-12">
<label for="street" class="form-label">Stradă</label>
<input id="street" class="form-control" name="street" type="text">
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-6">
<div class="card">
<div class="card-body">
<div class="col-lg-12 mb-3">
<label for="budget" class="form-label">Buget alocat</label>
<input id="budget" class="form-control" name="budget" type="text">
</div>
<div class="col-lg-12 mb-3">
<label for="payment_method" class="form-label">Metodă de plată</label>
<select id="payment_method" class="form-select" name="payment_method">
{% for value, label in form.fields.payment_method.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<hr class="border-secondary-subtle">
<div class="col-lg-12 mb-3">
<label for="urgency" class="form-label">Urgență</label>
<select id="urgency" class="form-select" name="urgency">
{% for value, label in form.fields.urgency.choices %}
{% if value == "Normal" %}
<option value="{{ value }}" selected>{{ label }}</option>
{% else %}
<option value="{{ value }}">{{ label }}</option>
{% endif %}
{% endfor %}
</select>
</div>
<div class="col-lg-12 mb-3">
<label for="deadline_date" class="form-label">Data limită</label>
<input id="deadline_date" class="form-control" name="deadline_date"
type="date" placeholder="ZZ.LL.AAAA">
</div>
<div class="col-lg-12 mb-3">
<label for="deadline_time" class="form-label">Ora limită</label>
<input id="deadline_time" class="form-control" name="deadline_time"
type="time" step="600" placeholder="OO:MM">
</div>
<div class="col-lg-12 mb-3">
<label for="assigned_listings" class="form-label">
Proprietăți asociate</label>
<select id="assigned_listings" class="form-control"
name="assigned_listings" multiple>
{% for value, label in form.fields.assigned_listings.choices %}
<option value="{{ value }}"></option>
{% endfor %}
</select>
</div>
<div class="col-lg-12 mb-3">
<label for="labels" class="form-label">Etichete</label>
<select id="labels" class="form-select" name="labels" multiple>
{% for value, label in form.fields.labels.choices %}
<option value="{{ value }}"></option>
{% endfor %}
</select>
</div>
<div class="col-lg-12">
<label for="notes" class="form-label">Notițe proprii</label>
<textarea id="notes" class="form-control" name="notes" type="text"
rows="4"></textarea>
</div>
</div>
</div>
</div>
<div class="card-footer">
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-subtle-success float-end">
Salvează cererea
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endif %}
{% endif %}
{% endblock content %}
{% block extra_javascript %}
<script>
document.addEventListener('DOMContentLoaded', function () {
console.log('Conținutul DOM a fost încărcat.');
var storedType = sessionStorage.getItem('selectedType');
var storedContactId = sessionStorage.getItem('selectedContact');
console.log('Tip cerere:', storedType);
console.log('ID contact:', storedContactId);
if (document.getElementById('property_type')) {
document.getElementById('property_type').value = storedType;
}
if (document.getElementById('contact')) {
document.getElementById('contact').value = storedContactId;
}
if (storedContactId) {
fetch('/contacts/api/contact-details/' + storedContactId)
.then(response => {
if (!response.ok) {
throw new Error('Eroare la solicitarea datelor contactului!');
}
return response.json();
})
.then(data => {
document.getElementById('firstName').innerText = data.first_name;
document.getElementById('lastName').innerText = data.last_name;
document.getElementById('phoneNumber').innerText = data.phone_number;
document.getElementById('email').innerText = data.email;
})
.catch(error => {
console.error('Eroare:', error);
});
}
var leadAssignedListings = document.getElementById('assigned_listings');
new Choices(leadAssignedListings, {
allowHTML: true,
loadingText: 'Se încarcă...',
noResultsText: 'Nu există proprietăți disponibile.'
});
var leadLabels = document.getElementById('labels');
new Choices(leadLabels, {
allowHTML: true,
loadingText: 'Se încarcă...',
noResultsText: 'Nu există alte etichete.'
});
document.getElementById('add_lead_form').addEventListener('submit', function(event) {
event.preventDefault();
var formData = new FormData(this);
console.log('Datele trimise sunt:', formData);
fetch('/leads/add-apartment-lead', {
method: 'POST',
body: formData,
})
.then(response => {
if (!response.ok) {
throw new Error('A apărut o eroare în timpul salvării.');
}
return response.text();
})
.then(data => {
console.log('Datele au fost salvate cu succes:', data);
window.location.href = 'lead-added';
})
.catch(error => {
console.error('Eroare în timpul salvării:', error);
});
});
});
</script>
{% endblock extra_javascript %}
我也尝试过使用 {{ form }} 但仍然不起作用。我注意到,我首先在上一页上选择联系人和属性类型,将这两个项目保存到 sessionStorage 中,但关键是整个表单看起来都是空的,就好像我实际上在表单上的任何字段中都没有任何内容一样.
html 文件不完整,因为它太长了,但是其中有很多重要字段,因此您可以弄清楚它的内容。完整的 html 页面可以在这里查看: https://github.com/dolca/crmSystem/blob/main/templates/leads/apartments/add_apartment_lead.html
提前致谢,感谢任何帮助!