Django createview创建没有外键的额外实例

时间:2020-10-09 22:47:06

标签: python django django-models django-forms

我正在使用Django createview在拍卖网站中创建出价项目。 createview将创建新对象,但会创建一个没有相应外键的额外对象实例。我正在使用@staticmethod来确定提交的出价是否确实是然后在相关清单中创建的最高出价。如果您能指出即时消息做错了什么,请先谢谢您。

models.py

class Bid(TimeStampMixin):
    """model representing bid obj"""
    auction = models.ForeignKey(
        Listing, 
        on_delete=models.SET_NULL, 
        related_name='offer', 
        null=True)
    bidder = models.ForeignKey(
        settings.AUTH_USER_MODEL, 
        on_delete=models.SET_NULL, 
        null=True,
        related_name='bid_user')
    amount = models.PositiveIntegerField()

    objects = BidQuerySet.as_manager()

        
    def __str__(self):
        return f"{self.amount} in Listing No: {self.auction.id}"

    class Meta:
        ordering = ['amount']

    @staticmethod
    def high_bid(auction, bidder, bid_amount):
        """util method to ascertain highest bid in auction then create in related auction obj
        :param auction---listing being bid on, bid__auction
        :param bidder---user bidding
        :param amount--- current highest bid
        """
        ###error checks, is auction running? is current bid less than start bid? etc
        if bid_amount < auction.start_bid:
            return
        if (auction.highest_offer and bid_amount < auction.highest_offer.amount):
            return
        if bidder.id is auction.user.id:
            raise PermissionDenied
        ##after checks create highest bid object in listing model
        new_high_bid = Bid.objects.create(
            auction= auction,
            bidder = bidder,
            amount = bid_amount
        )
        auction.highest_offer = new_high_bid
        auction.save()

class Listing(TimeStampMixin):
    user = models.ForeignKey(
        User, 
        on_delete=models.CASCADE, 
        related_name="seller")
    product = models.ForeignKey(
        Product, 
        on_delete=models.CASCADE, 
        related_name="item")
    start_bid = models.PositiveIntegerField(
        default=0)
    date_end = models.DateTimeField()
    duration = models.ForeignKey(
        Duration, 
        on_delete=models.SET_NULL, 
        null=True,
        blank=True,
    )
    ###static method in Bid model creates this
    highest_offer = models.ForeignKey(
        'Bid',
        related_name = 'highest_bid',
        on_delete = models.SET_NULL,
        null = True,
        blank = True,
    )

    def __str__(self):
        return f"Listing for {self.product} by {self.user}."

views.py

class BidCreateView(LoginRequiredMixin, CreateView):
    """View to create auction bid"""
    model = Bid
    form_class = BidForm
    template_name = "auction/auction_detail.html"

    ##define url redirected to when form is valid 
    def get_success_url(self):
        return reverse ('detail', kwargs = { 'pk' : self.auction.pk })

    ###get context data to be passed to view
    def get_context_data(self, **kwargs):
        bidder = self.request.user
        ###call parent class to init 
        c = super().get_context_data(**kwargs)
        c["auction"] = self.auction
        ###check if user is bidding on own item
        if bidder.id is self.auction.user.id:
            c["form"] = None
        return c

    ###get_form_kwargs() method to supply user and listing during form creation
    def get_form_kwargs(self):
        ###call parent class
        kwargs = super().get_form_kwargs()
        ###extrack PK from kwargs so we can query for related listing obj
        pk_ = self.kwargs.get('pk')
        auction = Listing.objects.get(pk = pk_)
        kwargs["auction"] = auction
        self.auction = auction
        print(kwargs)
        return kwargs

    def form_invalid(self, form):
        return super().form_invalid(form)

    def form_valid(self, form):
        bid_amount = form.cleaned_data["amount"]

        try:
        ###use transaction.atomic to tie this method with a succesful form submission
            with transaction.atomic():
                Bid.high_bid(
                    self.auction,
                    self.request.user,
                    bid_amount
                )
        except IntegrityError:
            messages.error(self.request, "An unexpected error has occured")

        messages.success(self.request, "Bid submitted successfully!")

        return super().form_valid(form)

forms.py

class BidForm(forms.ModelForm):
    class Meta:
        model = Bid
        fields = [
            'amount',
        ]

        widgets = {
            'amount' : forms.NumberInput(attrs={'class' : 'form-control'}),
        }

    def __init__(self, *args, **kwargs):
        """override __init__ pop related auction from kwargs"""   
        self.auction = kwargs.pop("auction", None)
        ##call super with related obj 
        super().__init__(*args, **kwargs)
        

    ##clean data/validate, ensuring bid is larger than highest bid and starting bid
    def clean_amount(self):
        amount = self.cleaned_data["amount"]
        ##check if less than starting bid
        if self.auction.start_bid > amount:
            raise ValidationError(_('Bid is less than starting bid'))
        if (self.auction.highest_offer.amount >= amount):
            raise ValidationError(_('Bid is less than current highest bid'))
        return amount

显示不带外键的额外出价对象的数据库表

DB table

1 个答案:

答案 0 :(得分:0)

从form_valid删除return super().form_valid(form)行。

这行代码将从继承的类中调用form_valid,该类将保存对象-这是没有外键创建的额外对象。

相反,您将需要返回某种http响应(例如render_to_response,重定向等)。