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

如何实现Django中同一餐桌不同时段可预订、同时段不重复?

实现同一餐桌同一时间不可重复预订的方案

先修正你现有模型里的两个核心问题:

  1. user字段用了OneToOneField,这会限制一个用户只能订一次桌,不符合实际需求,改成ForeignKey才对。
  2. 缺少预订日期字段,只存时间的话,不同日期的同一时间也会被判定为冲突,必须补上date字段。

1. 修改BookingTable模型

更新后的模型代码如下:

from django.db import models
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError

class BookingTable(models.Model):
    TIME_CHOICES =[
        ('08:00', '08:00'),
        ('09:00', '09:00'),
        ('10:00', '10:00'),
        ('11:00', '11:00'),
        ('12:00', '12:00'),
        ('13:00', '13:00'),
        ('14:00', '14:00'),
        ('15:00', '15:00'),
        ('16:00', '16:00'),
        ('17:00', '17:00'),
        ('18:00', '18:00'),
        ('19:00', '19:00'),
        ('20:00', '20:00'),
        ('21:00', '21:00'),
    ]
     
    table = models.ForeignKey(Table, on_delete=models.CASCADE)
    # 改成ForeignKey,支持用户多次预订
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    date = models.DateField()  # 添加预订日期字段
    time = models.TimeField(choices=TIME_CHOICES)

    class Meta:
        # 数据库层面添加联合唯一约束:同一餐桌、同一日期、同一时间只能有一条预订
        constraints = [
            models.UniqueConstraint(
                fields=['table', 'date', 'time'],
                name='unique_table_date_time'
            )
        ]

    def clean(self):
        super().clean()
        # 代码层面提前检测冲突,避免数据库抛错
        existing_booking = BookingTable.objects.filter(
            table=self.table,
            date=self.date,
            time=self.time
        ).exclude(pk=self.pk)  # 编辑预订时排除自身
        
        if existing_booking.exists():
            raise ValidationError(f"该餐桌在{self.date} {self.time}已被预订")

    def get_absolute_url(self):
        return reverse("list_tables")
       
    def __str__(self) -> str:
        return f"{self.user.username}-{self.table.name}-{self.date} {self.time}"

2. 表单层面添加友好验证提示

如果用ModelForm处理预订提交,在表单里补充验证逻辑,给用户更直观的错误提示:

from django import forms
from .models import BookingTable

class BookingTableForm(forms.ModelForm):
    class Meta:
        model = BookingTable
        fields = ['table', 'date', 'time']  # 根据需求调整显示字段

    def clean(self):
        cleaned_data = super().clean()
        table = cleaned_data.get('table')
        date = cleaned_data.get('date')
        time = cleaned_data.get('time')

        if table and date and time:
            existing = BookingTable.objects.filter(
                table=table,
                date=date,
                time=time
            ).exclude(pk=self.instance.pk if self.instance else None)
            
            if existing.exists():
                self.add_error('time', f"该餐桌在{date} {time}已被预订")
        
        return cleaned_data

3. 视图层处理提交逻辑

在视图里处理表单提交,捕获验证错误并返回给前端:

from django.shortcuts import render, redirect
from .forms import BookingTableForm

def create_booking(request):
    if request.method == 'POST':
        form = BookingTableForm(request.POST)
        if form.is_valid():
            booking = form.save(commit=False)
            booking.user = request.user  # 关联当前登录用户
            booking.save()
            return redirect('list_tables')
    else:
        form = BookingTableForm()
    return render(request, 'booking_form.html', {'form': form})

最后执行数据库迁移,让修改生效:

python manage.py makemigrations
python manage.py migrate

这样就能实现同一餐桌在同一日期同一时间只能被预订一次的功能,同时支持用户多次预订不同时间或不同餐桌。

内容的提问来源于stack exchange,提问作者lerton josine

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 10:57:36