Python 根据另一个模型验证表单字段

Python 根据另一个模型验证表单字段,python,django,django-models,django-forms,Python,Django,Django Models,Django Forms,我正在尝试建立一个拍卖网站,允许用户对物品进行竞价。用户若要成功出价,其输入的金额必须高于当前最高出价,如果由于尚未有用户出价而没有当前最高出价,则第一次出价输入必须高于挂牌起始价 如果输入不符合这些条件,我想向BidForm添加表单验证以引发错误,但在def clean_bid_输入中的listing.id上有一个pylint错误,它说这是一个未定义的变量,因此我觉得表单验证不太正确。请有人看看我的表单验证是否符合我希望的逻辑 型号.py class Listing(models.Model)

我正在尝试建立一个拍卖网站,允许用户对物品进行竞价。用户若要成功出价,其输入的金额必须高于当前最高出价,如果由于尚未有用户出价而没有当前最高出价,则第一次出价输入必须高于挂牌起始价

如果输入不符合这些条件,我想向BidForm添加表单验证以引发错误,但在def clean_bid_输入中的listing.id上有一个pylint错误,它说这是一个未定义的变量,因此我觉得表单验证不太正确。请有人看看我的表单验证是否符合我希望的逻辑

型号.py

class Listing(models.Model):

    class NewManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(status='active')

    options = (
        ('active', 'Active'),
        ('closed', 'Closed'),
    )

    title = models.CharField(max_length=64)
    description = models.TextField(max_length=64)
    start_price = models.DecimalField(max_digits=9, decimal_places=2, validators=[MinValueValidator(0.99)])
    image = models.URLField(max_length=200, blank=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="listings")
    lister = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="lister_user")
    date_added = models.DateTimeField(default=timezone.now)
    status = models.CharField(max_length=10, choices=options, default="active")
    winner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET(get_sentinel_user), related_name="winner_user", null=True)
    favourites = models.ManyToManyField(User, related_name="favourite", default=None, blank=True)
    objects = models.Manager()
    listingmanager = NewManager()

    def __str__(self): 
        return f"{self.title} ({self.pk}, £{self.start_price}, {self.lister})"    


class Bid(models.Model):
    bidder = models.ForeignKey(User, on_delete=models.CASCADE, related_name="bidders")
    bid_item = models.ManyToManyField(Listing, related_name="bid_items", default=None)
    bid_input = models.DecimalField(max_digits=9, decimal_places=2, default=None)
    time = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return f"Bid amount: {self.bid_input}"
class NewListingForm(forms.ModelForm):
    class Meta:
        model = Listing
        fields = ["title", "description", "start_price", "image", "category"]

    title = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
    description = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
    start_price = forms.DecimalField(label='Starting Bid Price (£)')
    image = forms.URLField(widget=forms.URLInput(attrs={'autocomplete':'off'}))
    category = forms.ModelChoiceField(queryset=Category.objects.all())
    

class BidForm(forms.ModelForm):
    class Meta:
        model = Bid
        fields = ["bid_input"]
        labels = {"bid_input": ""}
        widgets = {
            "bid_input": forms.NumberInput(attrs={'placeholder': 'Enter bid (£)'})
        }
    
    def clean_bid_input(self):
        data = self.cleaned_data['bid_input']
        highest_bid = Bid.objects.filter(bid_item=listing.id).aggregate(Max('bid_input'))
        listing_price = Listing.start_price.get(bid_item=listing.id)
        if highest_bid is None:
            if data < listing_price:
                raise ValidationError('Bid must be higher than listing start price')
        if data < highest_bid:
            raise ValidationError('Bid must be higher than current highest bid')
forms.py

class Listing(models.Model):

    class NewManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(status='active')

    options = (
        ('active', 'Active'),
        ('closed', 'Closed'),
    )

    title = models.CharField(max_length=64)
    description = models.TextField(max_length=64)
    start_price = models.DecimalField(max_digits=9, decimal_places=2, validators=[MinValueValidator(0.99)])
    image = models.URLField(max_length=200, blank=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="listings")
    lister = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="lister_user")
    date_added = models.DateTimeField(default=timezone.now)
    status = models.CharField(max_length=10, choices=options, default="active")
    winner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET(get_sentinel_user), related_name="winner_user", null=True)
    favourites = models.ManyToManyField(User, related_name="favourite", default=None, blank=True)
    objects = models.Manager()
    listingmanager = NewManager()

    def __str__(self): 
        return f"{self.title} ({self.pk}, £{self.start_price}, {self.lister})"    


class Bid(models.Model):
    bidder = models.ForeignKey(User, on_delete=models.CASCADE, related_name="bidders")
    bid_item = models.ManyToManyField(Listing, related_name="bid_items", default=None)
    bid_input = models.DecimalField(max_digits=9, decimal_places=2, default=None)
    time = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return f"Bid amount: {self.bid_input}"
class NewListingForm(forms.ModelForm):
    class Meta:
        model = Listing
        fields = ["title", "description", "start_price", "image", "category"]

    title = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
    description = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
    start_price = forms.DecimalField(label='Starting Bid Price (£)')
    image = forms.URLField(widget=forms.URLInput(attrs={'autocomplete':'off'}))
    category = forms.ModelChoiceField(queryset=Category.objects.all())
    

class BidForm(forms.ModelForm):
    class Meta:
        model = Bid
        fields = ["bid_input"]
        labels = {"bid_input": ""}
        widgets = {
            "bid_input": forms.NumberInput(attrs={'placeholder': 'Enter bid (£)'})
        }
    
    def clean_bid_input(self):
        data = self.cleaned_data['bid_input']
        highest_bid = Bid.objects.filter(bid_item=listing.id).aggregate(Max('bid_input'))
        listing_price = Listing.start_price.get(bid_item=listing.id)
        if highest_bid is None:
            if data < listing_price:
                raise ValidationError('Bid must be higher than listing start price')
        if data < highest_bid:
            raise ValidationError('Bid must be higher than current highest bid')
类NewListingForm(forms.ModelForm):
类元:
模型=列表
字段=[“标题”、“说明”、“起始价格”、“图像”、“类别”]
title=forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
description=forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
起始价格=表格。分码字段(标签=‘起始投标价格(£)’)
image=forms.URLField(widget=forms.URLInput(attrs={'autocomplete':'off'}))
category=forms.ModelChoiceField(queryset=category.objects.all())
类BidForm(forms.ModelForm):
类元:
模型=投标
字段=[“投标输入”]
标签={“bid_输入”:“”}
小部件={
“投标输入”:forms.NumberInput(属性={'placeholder':'输入投标(£)})
}
def清洁投标输入(自):
数据=自清理数据['bid\U input']
最高出价=bid.objects.filter(bid\u item=listing.id).aggregate(Max('bid\u input'))
listing\u price=listing.start\u price.get(bid\u item=listing.id)
如果最高投标为无:
如果数据<挂牌价格:
raise ValidationError('出价必须高于挂牌起始价')
如果数据<最高出价:
raise ValidationError('出价必须高于当前最高出价')

clean\u bid\u input
方法中替换此:

listing\u price=listing.start\u price.get(bid\u item=listing.id)

用这个


listing\u price=listing.objects.get(bid\u item=listing.id).start\u price

谢谢,但我仍然在listing上遇到一个红色下划线错误。id
listing.id
未定义,因为它尚未设置。在
clean\u bid\u input
方法中没有对
列表
对象实例的引用。为了解决这个问题,我将在您的
BidForm
表单字段中添加一个输入
bid\u项
(您可以将其隐藏)。因此,您可以使用
bid\u item
字段的清理数据在
clean\u bid\u input
方法中获得
列表
对象实例。我相信有更好的方法,但我不知道如何进一步帮助您,抱歉:(