Django关联AuctionListings拍卖模型与Bids出价模型及迁移报错解决
问题原因梳理
- 迁移报错直接原因:你现有数据库中已经存在
AuctionListings的历史数据,current_bid字段定义为非空的PositiveSmallIntegerField且没有设置默认值,Django迁移时无法给已有的旧数据填充该字段的值,因此抛出报错。 - Bids模型设计逻辑错误:当前的
Bids模型字段关联完全不符合需求:bid_price是出价金额,应为数值类型,不应该设置为关联AuctionListings的外键- 单条出价记录仅对应一个拍卖商品,不需要额外设置
ManyToManyField关联AuctionListings,用单外键关联即可
具体解决步骤
步骤1:修复AuctionListings模型,适配eBay起拍价规则
class AuctionListings(models.Model): """ Model for all the listings listed on the site. """ title = models.CharField(max_length=40) description = models.TextField() image_url = models.URLField(blank=True) # 允许用户不上传商品图片 starting_bid = models.PositiveSmallIntegerField(verbose_name="起拍价") # 新增起拍价字段存储用户设置的起拍金额 current_bid = models.PositiveSmallIntegerField(verbose_name="当前最高价", default=0) # 新增默认值解决迁移报错 category = models.CharField(choices=CATEGORIES, max_length=5) # 原有日期字段无需修改直接保留 date = models.DateField(default=date.today) datetime = models.DateTimeField(default=timezone.now) date_last_updated = models.DateField(auto_now=True) date_added = models.DateField(auto_now_add=True) timestamp_last_updated = models.DateTimeField(auto_now=True) timestamp_added = models.DateTimeField(auto_now_add=True) def save(self, *args, **kwargs): # 新建拍卖品时,当前最高价默认等于起拍价,符合基础拍卖规则 if not self.pk and self.current_bid == 0: self.current_bid = self.starting_bid super().save(*args, **kwargs) def __str__(self): return f"Title:{self.title}, Date Added:{self.date_added}, Category:{self.category}" class Meta: verbose_name_plural = "Auction Listings"
原理说明:拆分起拍价和当前最高价两个字段分别存储,符合eBay类拍卖平台的规则;给
current_bid设置默认值0,迁移时会自动给旧数据填充该默认值,解决报错问题。
步骤2:重写Bids模型,实现正确关联和级联删除
class Bids(models.Model): """ Model to allow one to place bids on listings. """ listing = models.ForeignKey(AuctionListings, on_delete=models.CASCADE, related_name="bids", verbose_name="关联拍卖品") bidder = models.ForeignKey(User, on_delete=models.CASCADE, related_name="my_bids", verbose_name="出价人") bid_price = models.PositiveSmallIntegerField(verbose_name="出价金额") bid_time = models.DateTimeField(auto_now_add=True, verbose_name="出价时间") class Meta: verbose_name_plural = "Bids" ordering = ["-bid_time"] # 出价记录默认按时间倒序排列 def __str__(self): return f"{self.bidder.username} 对 {self.listing.title} 出价 {self.bid_price}"
原理说明:
- 用
listing外键关联AuctionListings,设置on_delete=models.CASCADE即可实现拍卖品删除时,所有关联的出价记录同步级联删除- 单条出价记录仅对应一个拍卖品、一个出价人,不需要多对多关联
bid_price改为数值类型存储实际出价金额
步骤3:执行迁移操作
如果你之前已经生成过未加默认值的迁移文件,按以下操作处理:
- 先删除应用
migrations文件夹下最新生成的、还未执行的编号最大的迁移文件 - 执行命令
python manage.py makemigrations重新生成迁移文件,此时current_bid已经设置了默认值,不会再弹出报错提示 - 执行命令
python manage.py migrate完成迁移即可
步骤4:补充出价校验逻辑(符合eBay规则)
用户出价时需要增加基础校验,示例逻辑可写在对应视图中:
def place_bid(request, listing_id): listing = get_object_or_404(AuctionListings, pk=listing_id) bid_amount = int(request.POST.get("bid_amount")) # 核心规则:出价必须高于当前最高价 if bid_amount <= listing.current_bid: return HttpResponse("出价必须高于当前最高价") # 生成出价记录 Bids.objects.create(listing=listing, bidder=request.user, bid_price=bid_amount) # 更新拍卖品当前最高价 listing.current_bid = bid_amount listing.save() return HttpResponse("出价成功")
内容的提问来源于stack exchange,提问作者Maybe
相关产品推荐
相关产品推荐

