You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何持续将保险合同剩余天数保存至数据库?

Looks like you're trying to build a car insurance contract system where policies can be paused/resumed, with remaining days calculated daily and stored. Let's break down the issues in your current code and fix this properly.

1. Fix Your Model Logic (The Core Issue)

Your current save() method has bugs (like a typo remainingdaysays) and incorrect date arithmetic (subtracting raw day values won't work for cross-month calculations). Let's rework the model to track necessary data for accurate remaining days:

First, update the Contrat model with additional fields to track suspension periods:

from datetime import timedelta, date
from django.db import models
from django.contrib.auth.models import User

class Contrat(models.Model):
    Statut_contrat = (
        ('Encours', 'Encours'),
        ('Suspendre', 'Suspendre'),
    )
    numero_de_contrat = models.CharField(max_length=10, unique=True, null=False, blank=False)
    statut_assurance = models.CharField(max_length=15, choices=Statut_contrat)
    vehicule = models.ForeignKey(Vehicule, on_delete=models.CASCADE)
    Conducteur = models.CharField(max_length=200)
    utilisateur = models.ForeignKey(User, on_delete=models.CASCADE)
    nombre_de_mois = models.IntegerField()
    montant_du_contrat = models.DecimalField(max_digits=10, decimal_places=2)
    categorie = models.ForeignKey(Categorie_Contrat, on_delete=models.CASCADE)
    created = models.DateField(auto_now_add=True)
    modified = models.DateField(auto_now=True)
    active = models.BooleanField(default=True)
    remainingdays = models.IntegerField(null=True)
    
    # New fields for suspension tracking
    expiry_date = models.DateField(null=True)  # Contract end date
    total_suspension_days = models.IntegerField(default=0)  # Total days paused
    suspension_start_date = models.DateField(null=True, blank=True)  # When pause started

    def __str__(self):
        return self.numero_de_contrat

    def activeStatus(self):
        # Update active status based on remaining days
        return self.remainingdays > 0 if self.remainingdays is not None else True

    def save(self, *args, **kwargs):
        # Set expiry date on first save (if not already set)
        if not self.expiry_date:
            # Add nombre_de_mois months to created date (handle edge cases for month transitions)
            month_add = self.created.month + self.nombre_de_mois
            year_add = self.created.year + (month_add // 12)
            month_final = month_add % 12 or 12
            # Handle days for months with fewer days (e.g., Feb)
            try:
                self.expiry_date = self.created.replace(year=year_add, month=month_final)
            except ValueError:
                # If day doesn't exist in target month, use last day of month
                self.expiry_date = self.created.replace(year=year_add, month=month_final, day=1) - timedelta(days=1)
        
        # Handle status transitions
        if self.statut_assurance == 'Suspendre' and not self.suspension_start_date:
            # Start of suspension: record the date
            self.suspension_start_date = date.today()
        elif self.statut_assurance == 'Encours' and self.suspension_start_date:
            # End of suspension: calculate days paused and add to total
            pause_duration = (date.today() - self.suspension_start_date).days
            self.total_suspension_days += pause_duration
            self.suspension_start_date = None  # Reset start date
        
        # Calculate remaining days
        if self.expiry_date:
            # Adjust current date by subtracting total suspension days (since those days don't count)
            adjusted_current_date = date.today() - timedelta(days=self.total_suspension_days)
            remaining = (self.expiry_date - adjusted_current_date).days
            self.remainingdays = max(0, remaining)  # Don't let it go negative
        
        # Update active status based on remaining days
        self.active = self.remainingdays > 0
        
        super(Contrat, self).save(*args, **kwargs)

2. Simplify Your View Logic

Your current view has redundant calculations and incorrectly updates all contracts with the same numero_de_contrat (which should be unique). Let's clean it up:

from django.shortcuts import get_object_or_404, redirect, render
from .models import Contrat
from .forms import ContratAddFrom  # Assume your form is defined correctly

def ContratUpdate(request, id=None):
    detail = get_object_or_404(Contrat, id=id)
    if request.method == 'POST':
        form = ContratAddFrom(request.POST, instance=detail)
        if form.is_valid():
            form.save()  # The model's save() method handles remainingdays automatically
            return redirect('assurance_auto:Contrat_Liste')
    else:
        form = ContratAddFrom(instance=detail)
    
    return render(request, 'auto/UpdateContrat.html', {'form': form})

3. Implement Daily Remaining Days Update

Since you need to update remainingdays daily (even if no user edits the contract), you'll need a scheduled task. Here's a simple implementation using django-crontab:

  1. Install the package:
pip install django-crontab
  1. Add it to INSTALLED_APPS in your settings.py:
INSTALLED_APPS = [
    # ... your other apps
    'django_crontab',
]
  1. Create a management command to update all contracts:
    Create yourapp/management/commands/update_remaining_days.py:
from django.core.management.base import BaseCommand
from datetime import date, timedelta
from yourapp.models import Contrat

class Command(BaseCommand):
    help = 'Updates remaining days for all active contracts'

    def handle(self, *args, **kwargs):
        contracts = Contrat.objects.filter(active=True)
        for contrat in contracts:
            # Recalculate remaining days (matches model save logic)
            if contrat.expiry_date:
                adjusted_current_date = date.today() - timedelta(days=contrat.total_suspension_days)
                remaining = (contrat.expiry_date - adjusted_current_date).days
                contrat.remainingdays = max(0, remaining)
                contrat.active = contrat.remainingdays > 0
                contrat.save(update_fields=['remainingdays', 'active'])
        self.stdout.write(self.style.SUCCESS('Successfully updated remaining days'))
  1. Add the cron job to settings.py (runs daily at midnight):
CRONJOBS = [
    ('0 0 * * *', 'yourapp.management.commands.update_remaining_days'),
]
  1. Activate the cron job:
python manage.py crontab add

Key Notes

  • Date Accuracy: The expiry date calculation handles edge cases like months with different day counts (e.g., January to February). Adjust if you need stricter business rules (e.g., exact 30-day months).
  • Suspension Handling: When a contract is paused, we stop counting days by adding the pause duration to total_suspension_days, which adjusts the "effective" current date for remaining days calculation.
  • Daily Updates: The cron job ensures remaining days are updated even when no user interacts with the contract.

内容的提问来源于stack exchange,提问作者Mohamed Abdillah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:50:45