Reputation: 537
I'm new to Django (1.9.6) and I'm trying to understand if it is possible to validate a field on a ModelForm that needs to reference information that is contained in a Foreign Key from the referenced model.
How can I validate that the value a user inputs for "num_tickets" on the OrderForm is less than or equal to the "tickets_remaining" field on the Event class which is connected through a foreign key relationship?
I don't want to expose the Event field from the Order class on the OrderForm as the user has already accessed the specific event page, and has already selected to purchase tickets.
Models.py
class Order(models.Model):
first_name = models.CharField('First Name', max_length=120,null=False, blank=False)
last_name = models.CharField('Last Name', max_length=120, null=False, blank=False)
email = models.EmailField('Email', null=False, blank=False)
event = models.ForeignKey(Event)
num_tickets = models.PositiveIntegerField('Tickets', null=False, blank=False, validators=[MinValueValidator(0)])
total_price = models.DecimalField('Total', max_digits=8, decimal_places=2, default=0.0)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
class Event(models.Model):
event_name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=8, decimal_places=2, default=00.00, validators=[MinValueValidator(0)])
tickets_remaining = models.PositiveIntegerField(default=300)
Forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['first_name', 'last_name', 'email', 'num_tickets']
def clean_num_tickets(self):
tickets = self.cleaned_data["num_tickets"]
# validation Logic. Want to ensure a user cannot purchase more
# tickets than what an event has for "tickets_remaining"
return tickets
Upvotes: 0
Views: 893
Reputation: 599906
You don't show how you're associating the order with the event in the first place. If you haven't done that, then your problem is wider than just validating the tickets available.
I would recommend passing that Event from the view into the form instantiation. You can then use it both to associate the order with that event, and to validate the tickets.
class OrderForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event', None)
super(OrderForm, self).__init__(*args, **kwargs)
def clean_num_tickets(self):
tickets = self.cleaned_data["num_tickets"]
if tickets > self.event.tickets_remaining:
raise ValidationError('Too many tickets')
return tickets
def save(self, commit=False):
order = super(OrderForm, self).save(commit=False)
order.event = self.event
if commit:
order.save()
return commit
Now pass the event into the form when instantiating it:
form = OrderForm(request.POST, event=event)
Upvotes: 1