Django - Как обрабатывать ошибку повторяющегося значения для автоматического создания уникального значения - PullRequest
0 голосов
/ 10 июля 2020

В настоящее время в моем поле request_number модели ServiceRequest по умолчанию используется число шесть di git, сгенерированное функцией "number" (YY + 4 di git порядковый номер). Учитывая ожидаемое количество пользователей, потенциально создающих запросы одновременно, велика вероятность возникновения ошибки из-за дублирования номеров запросов. В случае моего проекта сообщение об ошибке гласит: «Запрос на обслуживание с этим номером запроса уже существует».

Как мне обработать эту ошибку, чтобы автоматически увеличить номер запроса на 1 до следующего уникального запроса номер найден, затем сохранить?

models.py

from django.db import models
from django.utils.timezone import now
from django.urls import reverse
import datetime


def number():
    y2 = now().strftime('%y')
    last_request = ServiceRequest.objects.filter(
        request_number__startswith=y2
    ).order_by('-request_number').values_list('request_number', flat=True).first()
    if last_request is None:
        return f'{y2}0000'
    else:
        num = (int(last_request) + 1) % 10000
        return f'{y2}{num:04d}'

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
    )

    STATUS_CHOICES = (
        ('open_status', 'Open'),
        ('reopened_status', 'Reopened'),
        ('closed_status', 'Closed'),
        ('cancelled_status', 'Cancelled'),
        ('in_work_status', 'In Work')
    )

    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,
        db_index=True,
        default=number,
        unique=True,
        blank=True
    )

    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='open_status'
    )

    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()

    aircraft = models.CharField(max_length=20)
    
    NrcWorkOrder = models.CharField(
        max_length=10, 
        verbose_name='Work Order', 
        blank=True
    )
    
    NrcZone = models.CharField(
        max_length=10, 
        verbose_name='Zone', 
        blank=True
    )
    
    NrcItem = models.CharField(
        max_length=10, 
        verbose_name='Item', 
        blank=True
    )
    
    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()

class File(models.Model):
 
    files = models.FileField(
        verbose_name="Attachments",
        name="files",
        upload_to="files/")
    
    service_request = models.ForeignKey(
        ServiceRequest,
        on_delete=models.CASCADE
    )  
    # TODO ASSOCIATE UPLOADED FILES TO THE REQUEST INSTANCE THAT IS BEING CREATED WHEN LOADING THE FILE

    def __str__(self):
        return str(self.files)

    def get_absolute_url(self):
        return reverse('file_list')

    def delete(self, *args, **kwargs):
        self.files.delete()
        super().save(*args, **kwargs)

views.py

from django.shortcuts import render, redirect, reverse
from .forms import ServiceRequestForm, FileForm
from .models import ServiceRequest, File
import datetime


def esr_submit(request):
    files = File.objects.all()
    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()
        # request_form.save()
        # request_form = ServiceRequestForm()
        file_form = FileForm()
    
    if request.method == 'POST':
        if 'file_upload' in request.POST:
            file_form = FileForm(request.POST, request.FILES)
            if file_form.is_valid():
                file_form.save()

        if 'submit_request' in request.POST:
            request_form = ServiceRequestForm(request.POST)
            if request_form.is_valid():
                request_form.save()
                
    return render(
        request, 
        'esr_submit/esr_submit.html', 
        {'request_form': request_form, 
        'file_form': file_form, 
        'files': files
        }
    )

forms.py

from django import forms
from .models import ServiceRequest, File
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column


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.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
        # widgets = {
        #     'request_number': forms.HiddenInput(),
        # }
        fields = [
            'files',
        ]

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 %}
                        <span class="helper-text"></span>
                    </div>
                </form>
                <form method="post" enctype="multipart/form-data" id="file_upload">
                    <div class="col">
                        {% csrf_token %}
                        {{ file_form|crispy }}
                    </div>
                </form>
                <table class="table table-borderless" style="margin-top: 10px;">
                    <tbody>
                        {% for file in files %}
                            {% if file.files %}
                               <tr>
                                   <td class="w-50">
                                       <a href="{{ file.files.url }}" target="_blank">{{ file.files }}</a>
                                   </td>
                                   <td>
                                       <form method="post" action="{% url 'delete_file' file.pk %}">
                                           {% csrf_token %}
                                           <button type=submit  class="btn btn-danger btn-sm">DELETE</button>
                                       </form>
                                   </td>
                               </tr>
                            {% else %}
                            {% endif %}
                        {% endfor %}
                    </tbody>
                </table>
                <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="submit" name="save_draft" value="save_draft" id="save_draft" class="btn btn-primary" form="request_form">Save Draft</button>
                </div>
            </div>
        </div>
    </div>
{% endblock content%}

...