Django中预约挂号时如何实现Doctor模型的slots字段自增
解决Django预约成功时Doctor slots字段自增的问题
嘿,我来帮你梳理下当前代码里的问题,然后一步步解决它:
现有代码的几个核心问题
- incSlots方法未同步到数据库:你的
incSlots()方法只是修改了内存中Doctor对象的slots值,但没有调用self.save()把变更同步到数据库,所以就算调用了这个方法,数据库里的slots也不会更新。 - 表单对象引用错误:视图里直接用
form.doc是不对的——表单验证通过后,应该操作form.instance(这才是表单绑定的Appointment实例),再通过它关联到对应的Doctor对象。 - 并发竞态风险:如果多个用户同时预约同一位医生,直接用
slots +=1可能导致计数错误(比如两个请求同时读取到slots=5,都加1后存为6,最终数据库里只记录了6而不是正确的7)。
分步修正方案
1. 优化Doctor模型的slots更新逻辑(避免并发问题)
推荐用Django的F()表达式直接在数据库层面做字段自增,从根源避免竞态条件。我们可以更新模型方法:
from django.db.models import F class Doctor(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) qualifications = models.CharField(max_length=100) expertise = models.CharField(max_length=100, default='Cardiac') fee = models.IntegerField(default=500) slots = models.IntegerField(default=0) def incSlots(self): # 用F表达式直接在数据库层面自增,避免并发冲突 self.slots = F('slots') + 1 self.save() # 刷新对象,让内存中的值和数据库同步 self.refresh_from_db()
2. 修正Appointment视图的处理流程
表单验证通过后,先处理Doctor的slots更新,再保存Appointment实例:
def appointment(request): docname = request.POST.get('doc_name') if request.method == 'POST': form = AppointmentForm(request.POST) if form.is_valid(): # 先获取未保存的Appointment实例 appointment_instance = form.save(commit=False) # 拿到关联的Doctor对象 doctor = appointment_instance.doc # 调用模型方法更新slots(或直接用F表达式操作) doctor.incSlots() # 最后保存Appointment到数据库 appointment_instance.save() return redirect('success') else: print(form.errors) form = AppointmentForm(initial={"patient":request.user, "doc_name": docname}) return render(request, 'appointment.html', {'form': form})
额外注意点
- 你的Appointment模型里,
doc字段用了OneToOneField,这意味着一个医生只能被预约一次,这大概率不符合实际业务场景——通常一个医生可以对应多个预约,建议改成ForeignKey。 - 测试的时候可以多开几个窗口同时提交预约,验证slots是否能正确累加,确保没有并发计数错误。
内容的提问来源于stack exchange,提问作者Noman Azeem
相关产品推荐
相关产品推荐

