在Django中如何判断客户月度房产付款到期日已到并筛选待付款客户
Django房产分期订阅系统到期客户筛选实现方案
现有代码问题修正
首先梳理现有模型的两处可优化点:
Payment模型中时间字段为datetime,原get_pending_customer方法中误用created_at字段会触发字段不存在报错- 缺少每月固定还款额、还款周期规则的核心字段,无法直接计算到期时间
模型补充与功能实现
第一步:补充必要字段与核心方法
修改后的models.py完整代码如下:
from django.db import models from django.db.models import Sum from datetime import datetime, timedelta from decimal import Decimal from dateutil.relativedelta import relativedelta # 处理自然月偏移,避免28/30/31天误差 class Property(models.Model): """房产模型""" area = models.CharField(max_length=255) price = models.DecimalField(max_digits=17, decimal_places=2, default=0.0,) created_on = models.DateTimeField(auto_now_add=True) class Customer(models.Model): """客户模型""" name = models.CharField(max_length=255) prop_select = models.ForeignKey(Property, on_delete=models.SET_NULL, null=True) created_on = models.DateTimeField(auto_now_add=True) remaning_amount = models.DecimalField(max_digits=17, decimal_places=2, default=0.0) # 补充核心业务字段:每月固定还款额、首次还款到期日 monthly_payment = models.DecimalField(max_digits=17, decimal_places=2, default=0.0) first_due_date = models.DateField() def save(self, *args, **kwargs): if self.prop_select: property_price = self.prop_select.price payment_done_by_customer = Payment.objects.filter(customer=self).aggregate(Sum('amount'))['amount__sum'] or Decimal('0') self.remaning_amount = property_price - payment_done_by_customer super(Customer, self).save(*args, **kwargs) def is_payment_due(self): """判断当前客户当期还款是否到期""" # 已经结清的客户直接返回未到期 if self.remaning_amount <= 0: return False # 计算已完成还款次数 paid_count = self.payment.count() # 计算当期应还款日期:首次还款日叠加已还款次数对应的自然月 current_due_date = self.first_due_date + relativedelta(months=paid_count) # 若当前日期超过应还款日则判定为到期 return datetime.now().date() >= current_due_date def is_overdue(self): """判断客户是否到期未还款""" if not self.is_payment_due(): return False paid_count = self.payment.count() current_due_date = self.first_due_date + relativedelta(months=paid_count) # 检查到期日后是否有对应足额还款记录 has_paid = self.payment.filter(datetime__date__gte=current_due_date, amount__gte=self.monthly_payment).exists() return not has_paid @classmethod def get_overdue_customers(cls): """批量筛选所有逾期未还款的客户""" return [c for c in cls.objects.filter(remaning_amount__gt=0) if c.is_overdue()] class Payment(models.Model): """还款记录模型""" customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL, related_name='payment') datetime = models.DateTimeField(auto_now_add=True) amount = models.DecimalField(max_digits=17, decimal_places=2, default=0.0)
注:代码中使用的relativedelta来自python-dateutil第三方库,可通过pip install python-dateutil安装,用于解决2月、大小月天数不同导致的还款日偏移误差,如果你不需要精确到自然月,也可以直接用timedelta(days=30)替换
功能使用说明
- 获取所有当期付款已到期的客户:遍历所有未结清客户,调用
is_payment_due()方法,返回True即为到期客户 - 直接筛选所有到期未支付的客户:调用
Customer.get_overdue_customers()即可拿到结果列表 - 若数据量较大不需要单独判断单个客户状态,也可以直接通过Django ORM的
annotate和条件查询实现批量筛选,性能更高
内容的提问来源于stack exchange,提问作者afi
相关产品推荐
相关产品推荐

