Reputation: 3
I am working through a project creating a simple Django auction site and I am having difficulty overriding the init method in a Django modelform when creating a new Bid from the 'Detail' view and passing a related object(auction) & user.
I am trying to override the BidForm(forms.modelform) init method so i can pass the related 'Auction' object using kwargs.pop. I get the error 'TypeError: init() got an unexpected keyword argument 'auction''
Please suggest what i am doing wrong and point me in the right direction- Thank you in advance
Model
class Bid(TimeStampMixin):
""" Model representing a bid in an auction """
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 get_absolute_url(self):
return reverse('detail', args=[self.pk])
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 update in related auction obj
**auction---listing being bid on, bid__auction
**bidder---user bidding
**amount--- current highest bid
"""
###error checks, 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()
Form
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"""
auction = kwargs.pop('auction')
self.auction = auction
##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
View
class BidCreateView(LoginRequiredMixin, CreateView):
model = Bid
form_class = BidForm
template_name = "auction/auction_detail.html"
def get_context_data(self, **kwargs):
bidder = self.request.user
c = super().get_context_data(**kwargs)
c["auction"] = self.auction
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):
kwargs = super().get_form_kwargs()
pk_ = self.kwargs.get('pk')
auction = Listing.objects.get(pk = pk_)
kwargs = {
'auction' : auction
}
return kwargs
def form_invalid(self, form):
return super().form_invalid(form)
def form_valid(self, form):
bid_amount = form.cleaned_data["amount"]
try:
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)
Template
{% extends "auctions/layout.html" %}
{% load custom_tags %}}
{% block body %}
<div class="row">
<div class="col">
<div class="card" style="width: 40rem;">
<img src="{{ object.product.img_url }}" class="card-img-top" alt="item">
<div class="card-body">
<h5 class="card-title">{{ object.product.title }}</h5>
<p class="card-text">{{ object.product.desc }}</p>
</div>
<div>
<ul class="list-group list-group-flush">
{% for offer in object.offer.all %}
<li class="list-group-item">Highest Bid: {{ offer.amount|usd }}</li>
{% endfor %}
<li class="list-group-item">Listed By: {{ object.user }}</li>
<li class="list-group-item">Category: {{ object.product.category }}</li>
<li class="list-group-item">Auction ends: {{ object.date_end }}</li>
</ul>
</div>
{% if user.is_authenticated %}
<div class="card-body">
<div class="row">
<div class="form-group col-3">
<form action="{% url 'AuctionBid' pk=object.pk %}" method="post">
{% csrf_token %}
{{ bidform.as_p }}
<button type="submit" class="btn btn-primary">Place Bid</button>
</form>
</div>
<div class="form-group col-3">
#PASS
</div>
</div>
</div>
{% else %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
Traceback
Internal Server Error: /bid/2
Traceback (most recent call last):
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/contextlib.py", line 75, in inner
return func(*args, **kwds)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/views/generic/edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/views/generic/edit.py", line 140, in post
form = self.get_form()
File "/Users//.pyenv/versions/3.8.3/lib/python3.8/site-packages/django/views/generic/edit.py", line 33, in get_form
return form_class(**self.get_form_kwargs())
TypeError: __init__() got an unexpected keyword argument 'auction'
Upvotes: 0
Views: 4964
Reputation: 11
Why are you overriding the __init__
in the Meta
class? Shouldn't your BidForm
definition look more like
class BidForm(Form):
def __init__(auction, *args, **kwargs):
self.auction = auction
super().__init__(*args, **kwargs)
Upvotes: 1