0
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%}

I have a function based view with two forms. The first form collects request information, the second form collects any files the user "attaches" to the request. There is a File Upload Button (to save the file to the database), Submit Request Button (to post the request), and a Save Draft (to save a draft of the request to the database).

Below are the challenges that I have spent a week with no luck. Note: I started learning Python and Django in March 2020, so I am pushing my knowledge base as I develop this project.

My challenges:

  1. If there is no file selected when the Upload File button is clicked, I need to notify the user that no file has been selected - without losing any data typed into the request form.

  2. Currently, when the Upload File button is clicked, the page refreshes. I do not want to lose any data typed into the request form. How do I stop this from happening?

  3. Each time a file is uploaded, I need it to show the file link at the bottom of the request form, without losing any data typed into the request form.

  4. How do I save a draft of the request form in the event not all required fields are populated?

5
  • Have you considered using front-end validation with JavaScript? Commented Jul 7, 2020 at 12:15
  • Hello Arthur - I am very novice with JavaScript. Do you have a recommended article/link that I can read up on this topic? Commented Jul 7, 2020 at 12:24
  • youtube.com/watch?v=wvcORaD1MoI This looks promising Commented Jul 7, 2020 at 12:35
  • Arthur - how do I add the onfocusout attribute if I am developing the form using crispy forms (see forms.py)? Commented Jul 7, 2020 at 15:57
  • stackoverflow.com/questions/20999795/… so it would be: self.fields["FIELD"].widget.attrs["autofocus"]="" Commented Jul 7, 2020 at 17:02

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.