Django and Stripe Payments Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone welcome to another video in this one we're going to be showing how you can integrate stripe payments into a django project and you can follow along using the django stripe github repository link is in the description down below and there's this starter files branch that you can use to follow along with the starting code and so just clone this repository check out the starter files branch and you can go from there and the finished code you'll find here on the master branch so what i've done is i've cloned the repository i've got it open in vs code i've created a virtual environment activated it and installed the dependencies we're using latest version of django as of the time of this recording and that's it nothing else is really installed i can go and run the server and you should be able to see it run and here it is right so a blank django project that we can use going forward and so if you're new here please subscribe to the channel and like this video it does help push this video to other people and propagate this through the youtube algorithm which in turn lets me make more content like this for you for free so please do show your support for the channel and other than that i do want to let you know that there's a new course i've added to the learn.justjango.com site which is where we build a gumroad clone if you've never heard of gumroad before gumroad is a place where you can basically create a digital product and you can sell that product and get paid so it's like a marketplace for creators and it's very popular for selling things like ebooks and notion templates and airtable databases and just digital products and so we go and build a clone of this in the sense that you can create a product you can sell that product and get paid so we use stripe payments and we use stripe connect to actually handle the payouts to the different creators on the site so do check out learn.justjango.com if you want to follow along with that course and other than that let's get started with the video so to follow along you're going to need to have a stripe account once you're logged in you can then go to view your test data and you can go to developers and then api keys it's important because you're going to need api keys to follow along and to actually make use of stripe payments so here you'll find if you have already otherwise you're just going to need to create some api keys but if you do have them make sure you copy your publish key or publishable key and your secret key you're going to need both of those and i'm just going to put them in a dot env file for now but we're not going to make use of the dot envy file we're going to go into our settings.pi and all the way down at the bottom we're going to create some variables that are going to store those values so you're going to have your stripe public key which is just going to be blank for now you're going to have your stripe secret key and you're going to have a stripe web hook secret as well which we'll get to in a second but for now we're just going to make sure that we have stripe public key and stripe secret key so once you have those values go and fill them in over here and we can then actually start building out a very basic application to handle stripe payments so one example of a digital product that you can sell is if you go to justjango.com and you go to the django tutorial hub the tutorialhub is an airtable database so you purchase access to this database and once you purchase access to it you get an email with the url to the database so it's kind of like a secret url and that's just one way that you can distribute access to the product and it's really really simple because all we're doing is just handling the payment we wait for a web hook from stripe which is basically an event telling us that the payment was successful and based on that event we can then send the user an email telling them that here's the url to what you paid for and so this is really the simplest example of how to implement stripe payments it's a landing page and once you click on grabbing a lifetime deal or any of these purchase buttons it then takes you into the process on stripe checkout which is one of the tools you can use to handle payments so you can see this is stripe checkout and once you then go through the checkout process you'll then get access to the product so we're going to build something very similar to this where it's literally just a landing page of a product you're trying to sell and so what we're going to do is we're going to create a model to represent this product which is basically going to be called a product the product model and it's going to represent whatever the product is you want to sell in my case it could have been the django tutorial hub in your case it might be a notion template or even an ebook maybe you want to send an email with an attachment which is an e-book it could be literally anything even just a file so what i'm going to do is i'm going to create an app to handle this so i'm going to run manage.pi start app and i'm just going to call it let's say products all right so if we bring this up here here's our products app and we just need to register that in the settings so we'll just come over here and we're going to add products all right so once you have that there you can then go into the products app into models.pi and you're going to create a product model so it's going to inherit from django's model and first we're going to give it a name which we can say is a character field with a maximum length of let's do [Music] 100 characters and we can do the string method which is basically just going to return self.name all right this is our basic product if we think about what a product has or what the properties of a product are it has a price it might have some details about it a description but all of those semantics about the product can be handled in the landing page itself so you can basically build a template the landing page and just style it to look like whatever you wanted to look like and to market the product but the actual data that we need to store on the product here is really just the name maybe some very specific information that is required by stripe but most importantly we need to store the price so i'm going to have the price on here and i'm going to store it as an integer field and why i'm doing this is because i'm going to store the value in cents so meaning if the product costs 10 dollars we're going to store a thousand in here because ten dollars is a thousand cents and this is just good because stripes api takes the price in cents so if you're storing it in cents it's going to help when you deal with the api but also when you have to do calculations then you can just add prices or multiply them purely with the sense value and then create a display value that converts it from cents into dollars there are some opinions as to why it's better to do it like this but it's really up to you if you want to use a decimal field or you want to use like a float field that's fine i just prefer an integer field so just make sure you do the calculation correctly but i'm going to store a default value of 0 and this is already enough for us to work with the product and actually start with stripe so what i'm going to do is just register it here in the admin so from the models import product and we're going to register the product model okay so that's that we can then run manage.pi make migrations and then migrate right so that's our first migration and i'll then go and run the server as well and actually before we do that i'm just going to create a super user as well so create a super user right now we can go and run the server and we can also go and open up the stripe docs so what you want to do is go to stripe.com docs all right the stripe documentation gets updated all the time so unfortunately if you're watching this in a couple months or a year from now maybe most likely the stripe documentation is updated but don't be intimidated by it the general structure and products that are provided by stripe don't change that much so you just have to know where to look and so what you're going to do is you're going to go to either all products if you want to see all of the products and you can then navigate from there and in our case we want to deal with payments so we're just going to go to payments online payments or you can just click to go straight to payments there either way so there's different kinds of payments you can see here there's guides and really we're going to follow the guide for the one that's most applicable to what we want to do which in this case is just handle a once off payment and it's going to be an online payment so meaning they have to use their credit card online we're not sending them an invoice they have to be on the website and actually enter their car details there so you can see there's online payments in person subscriptions invoices we're dealing with online payments so you can click on that and there's different ways that you can implement it you can just go to accept online payments which is straight out the gate handle payments and then if you want to do more technical things and you have some custom sort of functionality you're looking for you can save a card during the payment you can set up payments for future dates so we're going to go with accept online payments it's the simplest thing to do and there's two ways you can go about this guide the first is with a pre-built checkout page and the second is a custom payment flow so the first one is using stripe checkout and we're going to do that one first because it's very simple to do and once we're done with that we can then show how to do a custom payment flow so you'll see here on the front end i have html selected and on the back end i have python selected so make sure you've got both of those selected and that'll just make sure the documentation is correct so the first thing we have to do is we have to install stripe which is the python package so we're going to make sure we do that we're going to stop the server here and i'm going to run pip install stripe we're also going to want to store that in our requirements.txt so i'm going to say put freeze into our requirements.txt and once you have that we then scroll down to creating a checkout session so what this is is basically a unique session for when the user is paying so you saw on the tutorialhub when i clicked the button there was a little loader and what happens is it's sending a request to the back end it's creating a unique checkout session using this exact call here and that returns a url which you then get redirected to but let's just take this one step at a time first we're going to basically do everything here this is a stripe example so we're going to have to modify it for django but really or what we want is we want to call the stripe api so make sure we copy all of that and we're going to go into our product views.pin we're going to create a view that looks very similar to this one here which is the create checkout session view so i'm going to get rid of the render call there and i'm going to import from django's views import view view is a very generic class based view that we can use to handle things like post requests and get requests it's a very simple bare bones view so what we're going to do is create a class based view for this and i'm going to call it the create checkout session view which inherits from this view we're going to handle the post request which is by using the post method and that just takes in self request args and keyword dogs and then we're going to go and paste everything that we copied there from the documentation so we need to import the stripe package to actually make use of it so we'll do that here at the top and we also need to configure stripe using our api keys so we need to import the django settings in order to do this so we're going to do from django.conf import settings what we then do is we configure the stripe api key and this is using your secret key that we defined in the django settings so we're going to do settings.stripe secret key this is very important make sure you are using the stripe secret key and that you have your variables configured in your djangosettings.pi file right so then we can come down here and we can take a look at what's happening so we're storing this stripe api call in a variable called checkout session and there's a couple arguments passed in here you can see payment method types which is card so that basically is what it says it is we're allowing the payment methods to include card payments and then we have line items and line items are the items that are actually being purchased so every item is a dictionary or an object that has some properties like price data and quantity quite simply is just one we're buying one of this product and the price data contains the currency usd the unit amount which is incense again so this is 2 thousand cents but actually twenty dollars and then you have product data which has the name in this case there's the name and then some images and the images is a list of publicly available images that can be loaded during the striped checkout now because i don't have any product images i'm actually going to get rid of this from the product data that just means that there won't be any images show in the stripe checkout but if you do have some images that are publicly available then do go and add them in here and then you can just have the product name and you can see that this already in terms of the line items is exactly what we've modeled in the product model we have the name and the price so what we're going to want to do is we're going to want to fetch our specific product model here and then pass in that product's price and name but just continuing we can see the mode is payment and then we have a success url and a cancel url the success url is the url on your domain that you get redirected to once the payment is successful and then likewise the council url is the url you get redirected to once the payment was cancelled so your domain is in this case a variable so i'm going to just make use of it and i'm going to say that it's our local host because we're not going to be deploying this to a live site so getting redirected back to our localhost is fine and i'm going to remove the dot html from here and we'll just make use of slash success and slash cancel okay we're going to need to create two django views to handle this as well but for now what we're going to do is return our checkout session id in a json response so json response is if you think of like an api it returns json data which is all we need from this view we don't need to return html or an actual template we just want to return one piece of data so what i'm going to do is i'm going to say from django.http import the json response and all the way at the bottom we're going to return a json response and that takes in an object or a dictionary and in this dictionary we're going to return exactly what the stripe documentation returns here which is the id and that is the checkout session id so go ahead and copy that as well and we're going to paste that in there right so id is the key checkout session is our variable here and we're grabbing the id from that this is important because we're going to use this id on the front inside of things so in our javascript and stripes javascript module will make use of this id and use it to redirect us to our unique stripe checkout session okay so we have our view here it's basically complete we just need to bring it into the urls so i'm going to do this in the root url configuration and i'll just remove that comment and i'm going to say from our products dot views import create checkout session view and this path is going to be create checkout session it's going to use that view and we're going to do dot as view because it's class based view and we'll say the name is create checkout session and now that we have this url here what i'm going to do is i'm going to go into our settings.pi and i'm going to come here to our templates and what we're going to do is we're going to add a directory that we're going to use to hold some of our templates now because this is one of the later versions of django we have the path module so what we can do is we can add our base slash templates like that and then what we can do is we can create a templates directory here and inside there i'm going to create a file which we'll call our landing.html let's say so this is going to be our landing page and what we're going to do is just put some basic html in here that just says that this is the best product ever and you should really buy it and this is the price this is what it what all the features are so all of those sort of details so we'll say here is our product we'll say buy now just something for now and inside our products we'll create another view here which is going to be a template view a very simple view and it's just going to render out that template we just created so this is going to be our product landing page view and this is going to be a template view so what we can do is we'll say from django.views.generic import the template view right so this is going to inherit from that template view and all we have to do is just specify the template name which is going to be our landing.html we can then bring this into our urls here just as we did with the previous one and here we'll create a path to the base path so basically just empty string like that it's going to use our product landing view dot as view and we can say name is let's say landing page right so what that means is now if we come back over here and we go to refresh then we have our product displaying over here and we can now continue with the tutorial here which is to now go on to the front-end side of things so i'm going to come scroll down a little bit here to our add and order preview page right so this is where we actually display the product and you could pretty much go and copy everything inside this little checkout.html here and we can put that inside our template that we created so you can paste that there and we're going to focus mainly on the javascript side of things but you can see here there's just some generic html with a buy button and all of the product information displayed over there now this is hard coded so if this is how you would want to do it and you're only going to sell one product then that's fine but we want to make it a little bit more dynamic which we'll handle soon but we want to take a look at the javascript side of things so first they load stripe.js which is in the head of the document so that just brings stripe into the document you then add a checkout button so that button is what stripe is going to look for if you press this button it's then going to trigger an event listener that will send a request to the back end so you can see it's a post request and it's going to our create checkout session view returns the json response and then calls the stripe dot redirect to checkout which is a stripe function and all it does is take in the session id and that comes from our django view which has got the session id in it and at this point you'll be redirected to that form where you submit all your credit card information and actually buy that product so that's what all of this does initialize stripe fetch the checkout session redirect to stripe and that's it all right so that's the end of the tutorial you have some test cards that we can use as well but now onto the django side of things there's a couple things we need to do to make this a little bit better first we're hard coding the public stripe key here whereas what we can do is we can add some context into this template so we can just define the get context data method and that is so we can update the context so i'm going to call context equal to super of our product landing page view and we're going to return that context at the end of this view but in between that we're going to update the context because it's a dictionary and we can pass in the stripe public key which is going to come from our settings and it's going to be the stripe public key so what that allows us to do is inside the template here we can replace this with a context variable which is our stripe public key cool so that's the first major improvement the second is the actual product information here so again if you have a product image then you can display it but i'm going to remove it from the document and inside here we're going to want to display the actual product name and product price so going back to our view here we actually want to fetch the product that we're dealing with so to fetch the product we need to first import that product so we're going to save from our models import the product model and then here we're going to say that our product equals product.objects.get and we could do where the name equals to some sort of hard-coded name so let's say we know that our product is called test product so we're going to fetch the product here and we're going to pass this product into the context and what that lets us do is inside the template we can then access the product name here so we can do product.name and we can then do the product price here now do keep in mind that the price is in dollars it's not in cents so we're going to need to display the actual dollar price we don't want to display it in cents so what i'm going to do is define a method called get display price and we will add that to our product model so we'll say define get display price and all we're going to do is return a string which we will format with self.price divided by 100 so that will basically return it in the dollar value and in here we're going to pass in a little bit of some magic here which basically rounds it to two decimals so that sort of string format says return with two decimals behind it so all of that's running if we come back over here to our product we can refresh but we don't have an existing product with that name so we're gonna go into the admin and we're gonna log in and create our product so this was called the test product let's say the price is a thousand then if we come back to our landing page we can see our test product displaying here and the actual display price in dollars the last piece to add here to finish this off is if we go back to the views we want our checkout session to actually have to do with the price and the product that we're checking out so right now if we go to our view in the or rather the url the checkout session doesn't have any way of being distinguished between what product is actually being checked out so what we can do is we can add a primary key here as a unique identifier for what product we're actually purchasing so what that means is inside this view we now have access to some keyword arcs here so we can say that the product id equals to self.keyword.ox of the primary key and we can then fetch that product using product.objects.get where the id equals to the product id and now we actually have that specific product so over here we can say product dot price and over here we can say product dot name so now we're actually dealing with the specific product instead of just some hard coded data and we just need to make sure that when we send the request to this view that we pass in the primary key so if we go back to this landing.html here in the javascript we're fetching this url which is also hard coded so we could actually replace this with a django url and inside that url we're going to pass create checkout session and we're going to pass the product id as the required argument for that view and we do have the product in the context so that lets us pass that in like that now something to be aware of is that whenever you send a post request you need to make sure you pass in the csrf token so one very quick way to do this is actually to pass in csrf token inside the template like this and then i'm just going to paste this coming from the django documentation which basically does a query selector where the name equals csrf middleware token and we grab the value from that which is stored in this csrf token and we then just have to add some headers into our fetch request here and the header we're going to add is the c s r f in capitals and then token and that csrf token value stored inside the headers like that so that will allow us to send the post request because we now have the csrf token so if we go back to our view we can actually print out the product to make sure that we are getting all the correct information and just before testing it i just want to make sure we have the success and cancel urls setup so in order to do that we need to create two more templates success.html and we'll just say success and then the last one is cancel.html which is cancelled okay so then we can use those two templates as views so inside here i'm going to create another template view which is going to be our success view and it's going to be another template view template name is success.html and then we can just duplicate that and create cancel view which is going to be cancel.html and we can then bring both of these into the urls here so we'll then create two paths the first one is going to be to cancel which is the correct path and we're going to use cancel view dot as view name is cancel and then create another one which is going to be success and that's going to use the success view and just make sure there's some commas there cool so we've got the views set up and that means that our create checkout session view should be ready to test so coming back over here i'm going to refresh this and i'm going to inspect the page and bring up the console and i'm going to click the checkout button there and we can see we get redirected here's our strike checkout view test product again there's the price of the product which is correct so we can enter a test email here pass in dummy credit card information hit pay and now we just wait to get redirected to the success url and there we go all right so we can see we're redirected to slash success there's the success there so we know that it was successful and we can always come back here to our payments to see that the payment actually came through and there we can see it ten dollars there's a customer email so we know that it was a successful payment but now we actually need to give access for what they just paid right so the easiest way to do this is just to send them an email and because you're selling a digital product that normally means sending them either the url to the product or the actual product itself which is a an ebook or some sort of file if it was a file that you wanted to keep secure on the actual application and make it that they have to log in to download then i'd recommend checking out the gumroad course because in that we set up the application so that you have to log in and you have to download the content from there but in this case what we can do is actually just send an email now what we need to do is we need to listen for stripe web hooks now a web hook is basically an event that is sent to you from whatever origin so in this case it is stripe that is sending us these events and we treat these events as basically a way to prove that something has happened so in this case we need to receive an event from stripe that tells us that the payment was successful right so once we received that event we then know that the payment was successful and we can then give access to that specific product we can't trust that landing on success means that they actually paid because again i can just refresh here and i'm on slash success so we need those events now coming back here to the documentation in this checkout page if you scroll all the way down to the bottom you'll see the section after the payment and fulfillment is the first link if you click on this it's going to open up a new page of the documentation which is to fulfill your orders and this has to do with webhooks so it says here now when a customer pays you need notification that you can fulfill the order so you're going to learn how to receive an event notification when the customer pays you you're going to learn how to handle the event you're going to use the stripe cli to quickly test the event handler and you can then optionally handle additional payment methods and turn on your vin handling production but we're not going to do this in production we're just going to get this working locally so first you're going to need to install the stripe cli so if you don't have it installed you can go through the install guide and basically it allows you to run some commands as if you were calling the api so you can then do this in the terminal so you if you are on a mac you can use homebrew or if you're on any other operating system if you're on windows linux you can use any of these to install the stripe cli and then once you have it you can then just log into stripe and it's very easy to log in you'll just get a pairing code and you'll then be prompted to enter that code in the browser and it'll then just magically connect and you can then run commands using the stripe cli so for example you can run strive customers create and there's a whole bunch of things but what we're mainly going to use it for is to listen to webhook events so back here in this guide once you have the stripe cli installed you can then run stripe status to see if all the services online so coming back here i'm going to open up another terminal and i'm going to run that command so stripe status so it says here a new version of the stripes available in my case if you do have the latest version you won't get this but i'm not going to upgrade right now it does tell me all services are online and with that we can then continue to use the stripe cli to listen for these webhook events so just continuing here in the documentation you first have to create your event handler so this is going to be a view a django view that will actually handle the events when stripe sends them to us so we're going to just copy this example and it does say it's using django this example and if i just close this i'm going to do it right here in our product views and we can just move this import here to the top so it's actually from here http response right so csrf exempt is something we can actually import it's not here in the example but you can import it from the top you go from django.views.decorators.csrf import csrf exempt right so we basically use csrf exempt to make the view not require a csrf token and that is important because whenever a post request is sent we need to use a csr token to verify the post request but because it's coming from stripe we will not be receiving a csrf token so we just make it exempt but we are going to add some security settings here to verify the webhook so what happens is here you can see we have the payload which is the request body and this is going to contain most of the information about the webhook and at the end we return an http response with the status being 200 so that stripe knows we received the event so i'm going to rename this to be called stripe webhook and if we come back here we run the cli here with stripe listen and it says dash dash forward to localhost and then in this case it's two four two but we're going to do it port 8000 and then it's slash webhook but we're going to create our own url to handle this view so let's take this view bring it into the urls i'm going to import it here and i'm going to create a path which is going to be to let's do webhooks slash stripe we're going to use the stripe webhook and we can say name stripe webhook we then take this i'm going to open up the terminal and we run stripe listen forward to localhost 8000 slash stripe webhooks or how it is here we hook stripe so stripe listen dash dash forward to local host port 8000 slash and just paste that in there cool i'm going to run that see that it then outputs this your waybook signing secret is this value here you're going to want to take that value and make sure you've got it in your settings.pi as the striper webhook secret as that's what we're going to use to verify that the events come from stripe right so you can see already there's a whole bunch of events that are being sent and this is from other projects not necessarily from what we're doing right now but we will start receiving events about what we're doing in a second so we need to go through the checkout as a customer and we should then receive the checkout session completed event which is what stripe sends whenever you go through the checkout right so coming back here i'm going to go through the checkout again and so i'm just going to run through this right we get redirected because it's a success again and there you'll see dot session dot completed and so we're going to try and listen for that specific event and when we do receive this event we'll then look at all the information that comes with it and give access to the user and based on the product and all these different things so i'm going to go back here and first we need to verify the events come from stripe so there's a couple things you need to do inside this function so i'm going to copy all of that i'm just going to close this and i'm going to paste all of that there right so there's some try statements we have the payload the signature header which is basically a header in the request that comes from stripe and we need the signature header as well as the payload and our endpoint secret which is actually in the stripe webhook secret that we have in our settings.pi file so we can do settings.stripe webhook secret all right we then store the event as this event variable and we have two accept calls here first if it's a value error which means that it's an invalid payload right so the actual data from the payload is not valid in that case we return a 400 status code and then another exception is if the verification of the signature fails so in that case it's not a valid signature and we also return a 400 status code other than that if both of these are okay then we will have the event which we can use going forward so coming back here after we fulfill the order here we handle the checkout.session.completed event which is this whole bit here so you'll see there's an if statement checking if the event type is checkout.session.completed and based on that we then grab all of the information from that so i'm going to paste all of that here and just tab it in so if the event type is checkout session completed we then have this object that we can look at so i'm just going to go and print the session and what i'm going to do is i'm going to test the event again so going through here we're going to go through the checkout process again and we should then receive an event which we can then look at the contents of right we have a success we come back here and i'm going to go to our python server and we should see the event being printed out and this is the event all right so or the session rather as we printed it out here so the session contains a whole bunch of stuff we have the customer which is the stripe customer the customer details we have the payment method types we have the amount that was actually paid we have the success url all the details of this event as well as the total here you can see a thousand so we know that it has been paid now so all we have to do is grab the email from the customer details and give access to this specific product but as you can see there isn't much information on the specific product how do we know which django product was purchased based on the event here so what we do is we use the metadata property to pass in some specific information that we want to pass through so we do that inside our session create method here so what i'm going to do is pass in metadata and this is a python dictionary and what i'm going to do is i'm going to pass in the product id and the product id is going to be our django product id so what that helps us with is back here in the event inside our metadata we will then have the product id inside this dictionary which we can then access inside the webhook and thus we now have the customer's email and the product id so we can then give access to that specific product to the specific user that just checked out so what we're going to do is we're going to first grab the customer email and then we're going to grab the product id so grabbing the customer email is going to come from the customer details and then email so that's going to be session customer details and then their email and the product id is going to come from the metadata and then the product id right which we can see would come from there so once we have the customer email we can then send them an email which we can do using the send mail function which comes from django so you can do this by just doing from django.cor dot mail import send mail and you can then send an email and we just pass in a couple arguments we'll say the subject is here is your product we'll say the message is thanks for your purchase here is the product you ordered we'll then have the recipient list being one email which is the customer email and then the from email is actually just going to be a made up email you can just do anything really and that's because we're not going to be sending real emails so the way that we do that is in the settings.pi we basically just add a setting here which is the email backend and we can specify to use the console backend which basically means that emails will be printed in the console instead of actually sent out as real emails so we just specify here django.core dot mail.backends dot console dot email back end right so that will then send emails in the console and we can then grab the specific product by saying product equals to product dot objects dot get id equals to the product id and you can then decide how you want to do this do you want to send the actual file attached to the product here in the email so meaning we could add like a file field so we could say the actual file is a models.file field and we can say upload to let's say product files right so you can decide do you want it to be an actual an email every single time with the file and that file contains whether it's a video or a pdf or an e-book or whatever the actual file is or you could have the url so you could say this is a url field and this is literally the url to the notion document or the a table database whatever the url is for the digital product and you can then just send that inside the email so it's up to you at this point i'm not going to handle it specifically so what i'm going to do is i'm going to put it to do which is basically going to be decide whether you want to send the file or the url i'm gonna do the url because it's a little bit easier the file you could always attach to the send mail function but again it's up to you so what i'm gonna do is i'm gonna make this an f string in the message and i'll just say the url is and then just output it with product dot url okay and so i just need to make migrations then so i'm going to run manage.i make migrations and actually before i do that i'm going to go back to the product model here and i'm going to make this blank and null and in the url i'll also no i'll actually make make this required so coming back here make migrations all right the default value for the product i'm going to specify as google so just google.com and i forgot the the apostrophe there right so made the migration now migrate that cool so every product has a url and that url in this case is google.com so what that means is when you receive the email here it's going to say the url is google.com there you go you now have access to the content but again this could be the a table database the notion document that anything you want to sell that is a private url that will be the product you all here this is just one way to do it you can decide how you want to handle it whether it's a file or some other kind of product but the main point here is to get the stripe payments working so at this point that's all we really need to do we have the product we have the customer we send the customer access to the product and that's it so let's go and try this out again i'm going to run the django server here and we do have the stripe cli running here so we're going to run through the checkout again and we should see that we get an email in the console when we're done i'm going to use the email testing 123 at gmail.com just so that we can see that being printed out in the console right successfully redirected and there we can see the email right so thanks for your purchase here is the product you ordered and we can see who it's being sent from which is matates.com and then we have the two email which is the email i just checked out with so you can see now we're sending an email to that user after they purchased and we should see the event here checkout session completed from stripe cli so now we have the web hooks working this is how to implement webhooks and that's how to use stripe checkout as a way to handle payments so really what we have working at this point is exactly how the checkout works for buying the django tutorial hub the only upgrade that you can go from here is if we come back to this tutorial here is to do a custom payment flow and so that means actually building the card form yourself so you can see here enter the card number your expiration date and the cvc and actually building the form right this is the custom flow so first we have to install the stripe package we've already done that so that's fine we then go on to create a payment intent this is something new this is what we need to do every time we actually want a person to go through using their credit card details and the payment intent as you can see it says here tracks the customer's payment life cycle so it keeps track of failed payment attempts and ensuring the customer is only charged once so we have to return what's called the client secret and this is something part of the intent object so we create the object on the server right by calling the stripe api start payment intent dot create and in this case you can see it's as simple as just passing in the amount and the currency that then returns an object and we use the client secret on the front-end side with javascript to continue with it let's go and grab all of this and we're going to go and create a django view that does exactly that so we'll do this and we're going to create a class based view it's going to be the stripe intent view it's going to inherit from the view and we're going to handle post requests so self request args and keyword dogs and we're going to paste all of the stuff here all right so just get rid of what's not necessary in this case what's happening is it's loading the request data inside the json loads function but what we're going to do is use the url instead of using json data so all that's happening is it's calling this function calculate order amounts which is based on the items we're only going to be doing one item which is the product so i'm going to copy the product here and we're going to get the product via the product id which again comes from the url so if we take a look at this view here it comes from soft.keyword.org and we grab the primary key like that we don't need to create a data object and like that we can then just do product dot price in the amount currency is usd and we're going to return a json response that has the client secret which comes from this intent object otherwise we will return a json object that has this error key which is going to be the string of the error right so like this we can bring this into the urls so i'm going to import this over here and this is going to be a path to create payment intent we're going to use stripe intent view dot as view and the name will be create payment intent we need to just remember to add the primary key in the url like that and so coming back here to the documentation we load the stripe.js in the head which we're already doing we then define the payment form which you can see here i'm going to copy this form and we're going to go into the template here for landing.html i'm going to zoom out a little bit and underneath the product above the or actually below the checkout button i'll do this right and then we'll say check out using custom payment flow right so we have a form here i'm just going to tab all of this in there's this div with an id of card element which is very useful for stripe to load the card elements inside of you can see there's a submit button and there's a paragraph tag for card errors and a result message as well and some of this is just done from the global css file so you really could just copy everything from this css file and add it as css now what i'm going to do is i'm going to just put it inside a style tag for now because to set up static files would be away from the point of this tutorial so you can see there's all the style inside the style tag and if i come back and refresh the page if i just come back here you can see this is what it looks like right so you have the checkout button which is from our stripe checkout and then you have the actual custom payment flow so coming back here if we go to i'll check out the html right so we define the form we initialize stripe which we're already doing we then fetch a payment intent so you can see here we run this query selector it says that the button becomes disabled and we then create the payment intent which is by sending a post request to the back end and in this case they're submitting the body but we're not going to do that and once you get a response from the server you'll then have the client secret which you can then use in the result of this callback function and you'll see it then goes on to the next step where it creates stripe elements which creates this card element and then that gets mounted into the div with an idf card element and there's a whole bunch of javascript stuff here so you have a form event listener for the submit button which then calls this pay with card function and that takes in all of these arguments which then calls a stripe api endpoint which is to confirm the card payment using the client secret and some configuration here that says the payment method is the card which is using all the card information you just entered and then there's some ui helpers and some other stuff here as well but i'm going to go and copy all of it actually because it just helps to complete everything so we're going to copy basically all of the stuff all right come back here scroll all the way down and i'm going to do this underneath the checkout button here so just paste this all there right so i'm just going to have to tab some things in here so this is where our things start this checkout button is using stripe checkout so we're not interested in that but all of this stuff here i'm just going to tab that in right so we don't need to look at the ui helpers because basically that just helps with animating the error and the loading button so we're not going to look at that and then we have the pay with card function which is called here using the client secret if we scroll up here we do need to add something into the headers which if you remember is the csrf token so make sure to grab that and paste it inside the headers like this i'm going to change this from being hard coded into a django url so i'm going to do url and it's going to be create payment intent and it needs to take in the product id as an argument for the url and we don't need this purchase anymore so the body of the request here doesn't need to be passed in we can actually get rid of it so get rid of that right so that looks to be everything we need to do so the server is running we can come and try this out to refresh here and just check the format right so you can see the form is loading if i put the cursor you can see into the card number right so i'll do that and we can just inspect to make sure we don't get any kind of errors so i'll do that hit pay you'll see the little loader so this is now creating the payment intent that gets redirected here and we then get this message here payment succeeded see the result in your stripe dashboard which if i just refresh here we can see the payment show up here but there's something missing and that is the customer email so if we come back here all of this is actually done we've styled the form and all of that is fine what we're most interested in is actually adding more information about the customer which we're not doing right now we're just passing in the credit card number and so that's what we want to do here by enabling this toggle to send an email receipt so that requires that we collect a customer's email address and that just brings in this extra input field here so you can see there it is inside the form i'm basically going to copy exactly that and we're going to go into the form and we're going to add it just like that right so above the card element div and immediately if we refresh the pager you can see there's the email address inside the form and coming back here to the documentation you then need to provide the email address inside this confirm card payment method right so that's in the javascript side of things you need to pass in the recipient or receipt email but now instead of passing this in as a receipt email what we want to do is make sure that the email is used to create the customer so the easiest way to do this is actually to make a little bit of a custom payment flow in terms of what happens here in the landing page and in the view so back here in the landing page what's happening is we are creating a payment intent once the page loads right so we're calling this fetch api call immediately once the page loads now what i'm going to do is i'm going to change it so that only once we click the button which is on the format event listener that it actually calls the fetch command and that in turn will call the back end which creates the payment intent so in doing that how that helps us is that then we can actually access the email from the form and pass that email here into the data so that we can create a stripe customer and attach that customer to the payment intent so how this is going to look is if we come back here what we're going to do is if we just look at this fetch call we can see here that inside the dot then function you have an element a card element created and the form we're going to cut all of that out and we're going to paste it basically right above the fetch command right so we can see here's the elements here's the style and the card i'm just going to tab this in a little bit and what we want to do is here on the submit event listener when we call this pay with card instead of that being called there we're going to call it back inside the dot then function and we're going to move the entire fetch call in here so that means now we listen for when the form is submitted to then create the payment intent which then will return all the json data which is passed into the payword card call which then takes in everything and continues as usual what that allows us to do then is here we can pass in a body and inside that body we're going to pass in the email that comes from the form so we can do json.stringify we're going to pass in the email and that email value is going to be the email from the form which is this here so immediately what we can do is we can come in here and we can actually print the request body to actually see what that looks like and then if we come back to this over here and we just put in a dummy email testattest.com we're not trying to do the payments we're just trying to get the email in the back end and just fix that up right and actually i don't think i refreshed so let me refresh the page here and just make sure that we are actually submitting the with the new javascript that we just wrote right if i hit pay then we come back over here and we can see here is the body you can see email and test at test.com what we can then do is using that body we can load that into json so we can call this the let's say request json let's say and we're going to call json.loads the request body so we need to import json to actually handle that so import json let's come back down here and what i'm going to do is print out the request json and do it again right i can actually resubmit this entire thing and we should see there's the email right now this is actually a json object that's been loaded so we can access the email from here if i print out the email now instead and i come back and hit pay we should see test.test.com right so now you can see this is how we got the email and using that email we can then create the stripe customer so we can say customer equals to stripe dot customer dot create and we just pass in the email which is going to be this request json email value so this is now a stripe customer which we can then attach to the payment intent and that payment intent will now have the email which we then can access in the webhook so to pass in the customer we can simply pass in customer like this which is the customer id so we can access the id like this and we can actually print the customer for you to just see what that object looks like so if we come back here hit pay then we just wait for the request right here's the object and the object has a bunch of stuff on it so if we scroll up just a little bit there you can see is the id which is this customer and so with that customer being passed in into the payment intent which then in turn gets used in the front end we then get a web hook which contains the customer email so let's go to the the webhook here and it's actually print out the session okay i'm going to just clear the terminal out a little bit and i'm going to refresh here as well and i'm going to use something different let's say something else at test.com right so we should see this email being printed out now goes through all the necessary stuff creates the payment intent we can see here there's something else at test.com but now our webhook is actually slightly different so if we go back to the stripe here you can actually see we're not getting that checkout succeeded anymore because we're not going through stripe checkout now we are going through just a normal payment intent so you can see here we're getting a bunch of different charges we're getting customer created which is good payment intent created payment intent succeeded and the charge succeeded as well so a bunch of different events getting called we're most interested in the payment intent succeeded event so if we go here to the event listener here in the web hook what we're going to do is we're going to say else if the event type equals to payment intent succeeded i'm then going to say the intent equals to event data object and i'm going to print the intent out as well so that we can see the intent but it's actually going to be pretty similar not the actual object but in terms of what we do is going to be pretty similar here for the intent as well so let's just open up the python server here again i'm going to hit pay even for the same email though and we should see the web hook be printed so let me refresh the server come back here and hit pay and we just listen for the events right here we can see that event get printed so if we just scroll up a little bit there's a whole bunch of stuff included in a payment intent and you can see here right so there's the amount we then have the different charges right so we can see all the charges on there but we're most interested in if we just come a little bit down we have the customer and using this customer we are going to fetch the customer details from the stripe api which will include the email and using that email we can then send the user access to that content so what this looks like is over here we're going to say this is the let's say stripe customer equals to the intent and we're going to grab the customer from that and that is on the object it's a little bit nested but it is there so with that we can then say we'll actually do this we'll say stripe customer id and we can say the stripe customer equals stripe dot customer dot retrieve the stripe customer id right and using that we can then access the email from there so we're gonna say the customer email equals to stripe customer email and the rest of it looks very very similar so we send an email with the customer's email here but we again need to get access to the product via some sort of metadata so we can do this again in the exact same way as we do with the session call by doing this inside the payment intent so here we will add some metadata which will again contain the product id and this is going to be the product id which you can either get from the url or you could access product.id either is fine so now you're passing in the metadata which then allows us to grab the product id from the metadata as well so just tabbing this in we have the intent which we can then grab the metadata product id from we can then grab the product and send the email in the exact same way as we were doing in the other event and so like this let's try and test this out again i know we've gone through quite a lot but to get this to work you do have to customize quite a lot of things so we've got the email here if i hit pay it's going to create a customer with this email it'll then send us the payment intent webhook which will contain some metadata and the customer's email so hitting pay we just wait for some events now right there we go we can see an email being printed out so the url is there and that kind of means that everything worked but we can just double check to see that the customer is here and the metadata is here so you've got product id being passed in there and like this you can start sending access to some digital products and you can just build a very basic product landing page where you can sell any kind of digital product whether it's an ebook video set of files or url to some sort of product and very very easily you can use django to handle everything from creating the product data storing it on a site and selling that product and doing any kind of customized post processing for once the payment has completed so you can see it's not really a lot of code you've got a couple of views to just handle the event coming from stripe and from there you can then do whatever you want you can send an email you could send an event to some other kind of api to trigger some other processes you can do all sorts of things and this is just kind of scraping the surface if you've gotten any kind of value out of this video please consider liking the video again it does help push this channel forward and if you want to see more like this then do check out learn.justjango.com where we take this concept even further and show how we can pay multiple creators on the site and other than that thanks for watching don't forget to subscribe and i'll see you in the next video [Music] you
Info
Channel: JustDjango
Views: 29,512
Rating: undefined out of 5
Keywords: django, django tutorial, django stripe, django stripe tutorial, django stripe payments, django stripe checkout
Id: 722A27IoQnk
Channel Id: undefined
Length: 70min 26sec (4226 seconds)
Published: Thu Feb 11 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.