Building a Food Delivery App With Django and Python 3: Part 3 Building the Ordering System Part 2
In this video we are going to finish our ordering system by adding some fields for the name, email, and address. We will add a modal asking the user to confirm their order before submitting as well. Finally, we will add a feature to send a confirmation email to the user once the order is submitted. This will give us much more functionality for the ordering system that will make it more user friendly as well as get some more important details that we didnt’ get last time.
First, we need to update our models.py for these extra fields:
class OrderModel(models.Model):
created_on = models.DateTimeField(auto_now_add=True)
price = models.DecimalField(max_digits=7, decimal_places=2)
items = models.ManyToManyField('MenuItem', related_name='order', blank=True)
name = models.CharField(max_length=50, blank=True)
email = models.EmailField(max_length=50, blank=True)
street = models.CharField(max_length=50, blank=True)
city = models.CharField(max_length=50, blank=True)
state = models.CharField(max_length=15, blank=True)
zip_code = models.IntegerField(blank=True, null=True) def __str__(self):
return f'Order: {self.created_on.strftime("%b %d %Y %I:%M %p")}'
Now with those fields added, let’s go into our orders.html template and add some fields at the bottom before submitting and right after the end of our for loop for our drinks:
<div class="form-group pt-3">
<label for="name">Full Name</label>
<input required class="form-control" type="text" placeholder="Your Name" name="name" />
</div> <div class="form-group pt-3">
<label for="email">Email Address</label>
<input required class="form-control" type="text" placeholder="example@company.com" name="email" />
</div> <div class="form-group pt-3">
<label for="street">Street Address</label>
<input required class="form-control" type="text" placeholder="1234 Main St" name="street" />
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
<div class="form-group pt-3">
<label for="city">City</label>
<input required class="form-control" type="text" placeholder="San Francisco" name="city" />
</div>
</div>
<div class="col-md-4 col-sm-12">
<div class="form-group pt-3">
<label for="state">State</label>
<input required class="form-control" type="text" placeholder="CA" name="state" />
</div>
</div>
<div class="col-md-4 col-sm-12">
<div class="form-group pt-3">
<label for="zip">Zip Code</label>
<input required class="form-control" type="text" placeholder="94117" name="zip" />
</div>
</div>
</div>
All we are doing here is adding some input text fields and a label. It is important to note that we are adding a name attribute as well. This name attribute is what we will use to pull out the value in our python code in the views.py file so make sure this name attribute matches what you will type in the views file later. We are also adding ‘required’ which will throw an error if we try submitting the order with a blank field, bootstrap will handle the styles for this without us needing to do anything.
Now that we got those fields added, let’s add a modal to submit the form. So instead of having the submit order button where it is, we are going to change that to a modal that asks us to submit again to make sure the customer is ready. First let’s add the button to open the modal:
<button type="button" class="btn btn-dark" data-toggle="modal" data-target="#submitModal">Submit Order
</button>
Now let’s add our modal:
<!-- Modal -->
<div class="modal fade" id="submitModal" tabindex="-1" role="dialog" aria-labelledby="submitModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="submitModalLabel">Submit Your Order!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">Go Back</button>
<button type="submit" class="btn btn-dark">Place Order!</button>
</div>
</div>
</div>
</div>
Now we should be able to click the first button that opens up a modal that has the actual submit button to submit the form.
Now that we have these two features added, let’s add the changes to our post method in our views.py:
def post(self, request, *args, **kwargs):
# Get input fields at the bottom of the order template
name = request.POST.get('name')
email = request.POST.get('email')
street = request.POST.get('street')
city = request.POST.get('city')
state = request.POST.get('state')
zip_code = request.POST.get('zip') order_items = {
'items': []
} items = request.POST.getlist('items[]')
for item in items:
menu_item = MenuItem.objects.get(pk__contains=int(item))
item_data = {
'id': menu_item.pk,
'name': menu_item.name,
'price': menu_item.price,
}
order_items['items'].append(item_data)
price = 0
item_ids = [] for item in order_items['items']:
price += item['price']
item_ids.append(item['id'])
order = OrderModel.objects.create(
price=price,
name=name,
email=email,
street=street,
city=city,
state=state,
zip_code=zip_code
)
order.items.add(*item_ids) # After everything is done, send confirmation email to user
body = ('Thank you for your order! Your food is being made and will be delivered soon!\n'
f'Your total: {price}\n'
'Thank you again for your order!') send_mail(
'Thank You For Your Order!',
body,
'example@example.com',
[email],
fail_silently=False
) context = {
'items': order_items['items'],
'price': price
} return render(request, 'customer/order_confirmation.html', context)
At the top, we are using request.POST.get() to get the values from the post request. What we pass into this function corresponds to the name attribute in the input fields in our form. After this, we have all of our code from the last tutorial and then we create an actual OrderModel object. We pass in all of our data from the form. We use OrderModel.objects.create() which doesn’t require us to explicity save the object to the database, this is handled automatically.
Finally we need to import the send_mail function:
from django.core.mail import send_mail
Below creating an object, we send an email using send_mail, by passing in a subject, some body text, a ‘from’ email and a ‘to’ email. For this to work properly, we either need to set up our SMTP settings in our settings.py or we can add a line to send the email to the console. Since we are just in development and not in production, we will just send it to the console. So, lets open up or settings.py and add that:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
You can add this line anywhere to the file, I added it to the very bottom.
That’s all we will need to do to get these features working, we will come back in the future to add more to this application but we will stop here for today.