models.py
class ServiceRequest(models.Model):
CATEGORY_CHOICES = (
(None, ''),
('aircraft_repair', 'Aircraft Repair'),
('backshop', 'Backshop'),
('documentation', 'Documentation'),
('other', 'Other')
)
PRIORITY_CHOICES = (
(None, ''),
('1', 'Level 1 - Critical'), # <24 hours
('2', 'Level 2 - Urgent'), # 1-2 days
('3', 'Level 3 - Standard'), # 3-4 days
('4', 'Level 4 - Low') # 5+ days
)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False, blank=True)
updated = models.DateTimeField(auto_now=True)
request_number = models.CharField(max_length=6, default=number)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
contact = models.CharField(max_length=14)
category = models.CharField(max_length=20, choices=CATEGORY_CHOICES, default=None)
due_date = models.DateField(verbose_name='Due Date', auto_now_add=False, auto_now=False, blank=True)
priority = models.CharField(max_length=20, choices=PRIORITY_CHOICES, default='3') # default to standard priority
aircraft = models.CharField(max_length=20)
NrcWorkOrder = models.CharField(max_length=10, verbose_name='Work Order')
NrcZone = models.CharField(max_length=10, verbose_name='Zone')
NrcItem = models.CharField(max_length=10, verbose_name='Item')
EgWorkOrder = models.CharField(max_length=10, blank=True)
EgZone = models.CharField(max_length=10, blank=True)
EgItem = models.CharField(max_length=10, blank=True)
references = models.CharField(max_length=200)
description = models.TextField()
attachments = models.FileField(null=True, blank=True, upload_to=upload_location)
def __str__(self):
return self.request_number # show the request number in admin screen
class Meta:
ordering = ('-request_number',) # sort request number descending in admin screen
class File(models.Model):
files = models.FileField(verbose_name="Attachments", name="files", upload_to="files/", blank=True)
def __str__(self):
return self.files
def get_absolute_url(self):
return reverse('file_list')
def delete(self, *args, **kwargs):
self.files.delete()
super().save(*args, **kwargs)
forms.py
class ServiceRequestForm(forms.ModelForm):
class Meta:
model = ServiceRequest
fields = [
'first_name',
'last_name',
'email',
'contact',
'category',
'due_date',
'aircraft',
'NrcWorkOrder',
'NrcZone',
'NrcItem',
'references',
'description',
'request_number', # TODO remove before switching to production mode - should be hidden
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# self.fields['attachments'].widget.attrs.update({'input type': 'file', 'name': 'files', 'multiple': True})
self.helper = FormHelper()
self.helper.layout = Layout(
Row(
Column('first_name', css_class='input-large'),
Column('last_name', css_class='input-large'),
),
Row(
Column('email', css_class='input-large'),
Column('contact', css_class='input-large'),
),
Row(
Column('category', css_class='input-large'),
Column('aircraft', css_class='input-large'),
Column('due_date', css_class='input-large'),
),
Row(
Column('NrcWorkOrder', css_class='input-large'),
Column('NrcZone', css_class='input-large'),
Column('NrcItem', css_class='input-large'),
),
Row(
Column('references', css_class='input-large'),
),
Row(
Column('description', css_class='input-large'),
),
Row(
Column('request_number', css_class='input-large'),
),
)
class FileForm(forms.ModelForm):
class Meta:
model = File
fields = ['files']
urls.py
urlpatterns = [
path('', views.esr_submit, name='esr_submit'),
path('files/', views.file_list, name='file_list'),
path('files/<int:pk>/', views.delete_file, name='delete_file'),
]
views.py
def delete_file(request, pk):
if request.method == 'POST':
file = File.objects.get(pk=pk)
file.delete()
return redirect('file_list')
def file_list(request):
files = File.objects.all()
if request.method == 'POST':
form = FileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('file_list')
else:
form = FileForm()
return render(request, 'esr_submit/file_list.html', {
'files': files,
'form': form
})
def esr_submit(request):
if request.user.is_authenticated:
initial_data = {'first_name': request.user.first_name,
'last_name': request.user.last_name,
'email': request.user.email,
'contact': request.user.phone,
}
request_form = ServiceRequestForm(initial=initial_data)
file_form = FileForm()
else:
request_form = ServiceRequestForm()
file_form = FileForm()
if request.method == 'POST':
# request_form = ServiceRequestForm(request.POST, request.FILES)
# file_form = FileForm(request.POST, request.FILES)
if 'file_upload' in request.POST:
file_form = FileForm(request.POST, request.FILES)
if file_form.is_valid():
file_form.save()
# return redirect('esr_submit')
return render(request, 'esr_submit/esr_submit.html', {'request_form': request_form, 'file_form': file_form})
esr_submit.html
{% extends "main/base.html" %}
{% block title %}
Submit an ESR
{% endblock %}
{% load crispy_forms_tags %}
{% block content %}
<head>
</head>
<br>
<div class="container">
<div class="row justify-content-md-center mb-2">
<div class="col-sm-8 mb-4 shadow-lg p-3 bg-white rounded">
<div class="header mb-2">
<h3 class="header mb-0 text-center">New Engineering Service Request</h3>
{% if not request.user.is_authenticated %}
<div class="text-center">
<small class="text-muted"><strong>Want to speed things up? </strong><a href="/login/?next=/esr_submit/"> Log In |</a></small>
<small class="text-muted"><a href="/register/?next=/esr_submit/">Create an account </a></small>
</div>
{% endif %}
</div>
<form method="post" enctype="multipart/form-data" id="request_form">
<div class="col">
{% csrf_token %}
{% crispy request_form %}
</div>
</form>
<form method="post" enctype="multipart/form-data" id="file_upload">
<div class="col">
{% csrf_token %}
{{ file_form|crispy }}
</div>
</form>
<div class="pl-2">
<button type="submit" name="file_upload" value="file&upload" form="file_upload" class="btn btn-primary">Upload File</button>
<button type="submit" name="submit_request" value="submit&request" class="btn btn-primary" form="request_form">Submit Request</button>
<button type="button" name="#" value="#" class="btn btn-primary">Save Draft</button>
</div>
</div>
</div>
</div>
{% endblock content%}
我有两种形式的基于函数的视图。第一种形式收集请求信息,第二种形式收集用户“附加”到请求的任何文件。有一个“文件上传”按钮(用于将文件保存到数据库),“提交请求”按钮(用于发布请求)和一个“保存草稿”(用于将请求的草稿保存到数据库)。
下面是我整整一周没有运气的挑战。注意:我从2020年3月开始学习Python和Django,因此在开发此项目时会不断推广自己的知识库。
我的挑战:
如果单击“上传文件”按钮时未选择任何文件,我需要通知用户未选择任何文件-不会丢失在请求表中键入的任何数据。
当前,单击“上传文件”按钮时,页面将刷新。我不想丢失键入请求表中的任何数据。如何阻止这种情况发生?
每次上传文件时,我都需要它在请求表单的底部显示文件链接,而不会丢失在请求表单中键入的任何数据。
如果未填写所有必填字段,如何保存请求表草稿?