Есть ли способ отключить функции обновления (UpdateView) и удаления (DeleteView) по истечении определенного периода времени?

Я хочу добиться того, чтобы "отключить" возможность для пользователя обновлять или удалять запись после определенного периода времени. В моем приложении пользователь создает слот бронирования доставки, в рамках которого он указывает дату доставки delivery_date.

Требование: Пользователь не должен иметь возможность обновлять/удалять слот бронирования в течение 7 дней после delivery_date

Как бы я поступил в этом случае?

models.py

from django.db import models
from django.utils import timezone
from django.urls import reverse
from django.contrib.auth.models import User

class Customer(models.Model):
    username = models.ForeignKey(User,on_delete=models.CASCADE)
    name = models.CharField(max_length=20,null=True)

    def __str__(self):
        return self.name

# Create your models here.
class Booking(models.Model):
    customer_name = models.ForeignKey(Customer,on_delete=models.CASCADE,null=True)
    username = models.ForeignKey(User,on_delete=models.CASCADE)
    qty_plts = models.PositiveSmallIntegerField(default=1)
    cbm = models.PositiveSmallIntegerField(default=1)
    created_date = models.DateTimeField(default=timezone.now())
    delivery_date = models.DateField(null=True)
    delivery_time = models.TimeField(null=True)
    booking_number = models.CharField(max_length=50,unique=True)
    
    def __str__(self):
        return self.booking_number

    def save(self, **kwargs):
        if not self.booking_number:
            self.booking_number = f"{self.delivery_date:%Y%m%d}{self.delivery_time:%H%M}"
        super().save(**kwargs)

    def get_absolute_url(self):
        return reverse('bookmyslot:detail',kwargs={'pk':self.pk})

views.py

from django.shortcuts import render

# Create your views here.
from .models import Booking,Customer
from .forms import BookingForm
from django.urls import reverse,reverse_lazy
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import (ListView,DetailView,CreateView,UpdateView,DeleteView,TemplateView)


class AboutView(TemplateView):
    template_name = 'about.html'

class HomeView(TemplateView):
    template_name = 'index.html'

class BookingCreate(LoginRequiredMixin,CreateView):
    login_url = '/login'
    redirect_field_name = 'bookmyslot/booking_detail.html'
    model = Booking
    form_class = BookingForm

    def get_form_kwargs(self, **kwargs):
        form_kwargs = super(BookingCreate,self).get_form_kwargs(**kwargs)
        form_kwargs['username'] = self.request.user
        return form_kwargs

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.username = self.request.user
        self.object.save()
        return super().form_valid(form)


class BookingList(LoginRequiredMixin,ListView):
    login_url = '/login'
    model = Booking
    template_name = 'bookmyslot/booking_list.html'
    context_object_name = 'bookings'

    def get_queryset(self):
        if not self.request.user.is_staff:
            return Booking.objects.filter(username=self.request.user)
        else:
            return Booking.objects.all()

class BookingDetail(LoginRequiredMixin,DetailView):
    login_url = '/login'
    context_object_name = 'booking_detail'

    model = Booking
    def get_queryset(self):
        if not self.request.user.is_staff:
            return Booking.objects.filter(username=self.request.user)
        else:
            return Booking.objects.all()

class BookingUpdate(LoginRequiredMixin,UpdateView):
        login_url = '/login'
        template_name = 'bookmyslot/booking_form_update.html'
        model = Booking
        form_class = BookingForm

        def get_form_kwargs(self, **kwargs):
            form_kwargs = super(BookingUpdate,self).get_form_kwargs(**kwargs)
            form_kwargs['username'] = self.request.user
            return form_kwargs

class BookingDelete(LoginRequiredMixin,DeleteView):
    login_url = '/login'
    model = Booking
    success_url = reverse_lazy('bookmyslot:list')

forms.py

from django import forms
from bookmyslot.models import Booking,Customer
from bootstrap_datepicker_plus import DatePickerInput
import datetime as dt
from django.utils import timezone
from .utilities import check_free_time
import os


HOUR_CHOICES = [(dt.time(hour=x), '{:02d}:00'.format(x)) for x in range(7, 13)]

class BookingForm(forms.ModelForm):

    def __init__(self,*args,**kwargs):
        user = kwargs.pop('username',None)
        super(BookingForm,self).__init__(*args,**kwargs)
        self.fields['qty_plts'].label = "Quantity Of Pallets"
        self.fields['cbm'].label = "Shipment CBM"
        self.fields['delivery_date'].label = "Delivery Date"
        self.fields['delivery_time'].label = "Delivery Time"
        self.fields['customer_name'].label = "Customer Name"
        self.fields['customer_name'].queryset = Customer.objects.filter(username=user)

    def clean(self):
        cleaned_data = super(BookingForm,self).clean()
        cleaned_delivery_date = cleaned_data.get('delivery_date')
        cleaned_delivery_time = cleaned_data.get('delivery_time')
        booking_number = f"{cleaned_delivery_date:%Y%m%d}{cleaned_delivery_time:%H%M}"

        if Booking.objects.filter(booking_number=booking_number).exists():
            x = Booking.objects.filter(delivery_date=cleaned_delivery_date)
            occupied_slots = []
            for i in range(0,len(x)):
                occupied_slots.append(x[i].booking_number[-4:])
            all_slots = ['{:02d}00'.format(x) for x in range(7, 13)]
            available_slot = check_free_time(all_slots,occupied_slots)
            if available_slot:
                message = f"Requested slot is already booked, here are today's available times: {os.linesep.join(available_slot)}"
                raise forms.ValidationError(message)
            else:
                message = "There are no more slots available today, please choose another date"
                raise forms.ValidationError(message)

    class Meta:
        model = Booking
        fields = ('customer_name','qty_plts','cbm','delivery_date','delivery_time')
        widgets = {'delivery_date':DatePickerInput(options={"daysOfWeekDisabled":[0,6],"minDate":timezone.now().date().strftime('%Y-%m-%d')}),
                    'delivery_time':forms.Select(choices=HOUR_CHOICES)}

urls.py

from . import views
from django.urls import path

app_name = 'bookmyslot'

urlpatterns = [
    path('mybookings/',views.BookingList.as_view(),name='list'),
    path('mybookings/<int:pk>/',views.BookingDetail.as_view(),name='detail'),
    path('update/<int:pk>/',views.BookingUpdate.as_view(),name='update'),
    path('delete/<int:pk>/',views.BookingDelete.as_view(),name='delete'),
    path('new/',views.BookingCreate.as_view(),name='create'),
    path('',views.HomeView.as_view(),name='home'),
    path('about/',views.AboutView.as_view(),name='about')

]

booking_detail.html

{% extends 'bookmyslot/base.html' %}

{% block content %}

<div class="jumbotron">

  <h2>Booking Number: {{ booking_detail.booking_number }}</h2>
  <h3>Details:</h3>
  <p></p>
  {% if user.is_staff %}
  <p>Company Name: {{booking_detail.username}}</p>
  <p>Customer Name: {{ booking_detail.customer_name }}</p>
  <p>Quantity Of Pallets: {{ booking_detail.qty_plts }}</p>
  <p>CBM Of Delivery: {{ booking_detail.cbm }}</p>
  <p>Delivery Date: {{ booking_detail.delivery_date }}</p>
  <p>Delivery Time: {{ booking_detail.delivery_time }}</p>
  {% else %}
  <p>Customer Name: {{ booking_detail.customer_name }}</p>
  <p>Quantity Of Pallets: {{ booking_detail.qty_plts }}</p>
  <p>CBM Of Delivery: {{ booking_detail.cbm }}</p>
  <p>Delivery Date: {{ booking_detail.delivery_date }}</p>
  <p>Delivery Time: {{ booking_detail.delivery_time }}</p>
  {% endif %}
</div>

<div class="container">
  <a class="btn btn-primary" href="{% url 'bookmyslot:update' pk=booking_detail.pk %}">Update Booking</a>
  <a class="btn btn-danger" href="{% url 'bookmyslot:delete' pk=booking_detail.pk %}">Delete Booking</a>

</div>

{% endblock %}

Вы можете использовать динамическое @свойство для проверки, если бронирование осуществляется менее чем за 7 дней от даты доставки :

models.py from datetime import date, timedelta

class Booking(models.Model):
    # ...
    @property
    def can_be_altered(self):
        """Return True if delivery_date - 7 days >= 0 else return False"""
        return self.delivery_date - date.today() >= timedelta(7)

booking_detail.html

<!-- Disable button if can not be altered -->
<!-- You can replace the button with a warning message too -->

<div class="container">
    <a class="btn btn-primary" {% if booking_detail.can_be_altered is not True %} disabled {% endif %} href="{% url 'bookmyslot:update' pk=booking_detail.pk %}">Update Booking</a>
    <a class="btn btn-danger" {% if booking_detail.can_be_altered is not True %} disabled {% endif %} href="{% url 'bookmyslot:delete' pk=booking_detail.pk %}">Delete Booking</a>
    {% if booking_detail.can_be_altered is not True %}
    <small class="form-text text-muted text-warning">You can not delete or update this booking within 7 days before delivery date </small>
    {% endif %}
</div>
Вернуться на верх