Έφτιαξα μια περιοχή μελών στον ιστότοπό μου με τους Python και Django. Εδώ έμαθα.

Αποφάσισα ότι ήρθε η ώρα να αναβαθμίσω τον προσωπικό μου ιστότοπο προκειμένου να επιτρέψω στους επισκέπτες να αγοράσουν και να αποκτήσουν πρόσβαση στα μαθήματά μου μέσω μιας νέας πύλης.

Συγκεκριμένα, ήθελα ένα μέρος για τους επισκέπτες να εγγραφούν για λογαριασμό, να δουν τα διαθέσιμα μαθήματά μου και να αγοράσουν αυτά τα μαθήματα. Μόλις ένας χρήστης είχε αγοράσει ένα μάθημα, θα μπορούσε να έχει πρόσβαση σε όλο το περιεχόμενο του μαθήματος για πάντα.

Αυτό μπορεί να ακούγεται απλό στη θεωρία. Ωστόσο, χωρίς τη χρήση ιστότοπου ηλεκτρονικού εμπορίου όπως το Shopify, οι ιστότοποι μελών είναι εκπληκτικά περίπλοκοι.

Σε αυτό το άρθρο θα σας καθοδηγήσω στις αποφάσεις που έκανα και στην τεχνολογική στοίβα που χρησιμοποίησα για τη δημιουργία αυτού του νέου ιστότοπου, όπως:

  1. Πώς να αρχίσω?
  2. Ξεκινώντας ένα έργο Django
  3. Πώς να ρυθμίσετε μοντέλα Django
  4. Ενσωμάτωση πληρωμών Stripe
  5. Ανάπτυξη του νέου μου ιστότοπου σε μια παρουσία AWS EC2
  6. Πώς να κλωνοποιήσετε το CSS από μια υπάρχουσα σελίδα

Πώς να αρχίσω?

Όταν προσθέτετε μια νέα ενότητα στον ιστότοπό σας με ένα εντελώς νέο σύνολο χαρακτηριστικών, είναι λογικό να οργανώσετε αυτόν τον ιστότοπο ως υποτομέα του αρχικού σας ιστότοπου.

Ένας υποτομέας είναι ακριβώς όπως ακούγεται. Είναι ένας τομέας που ανήκει σε έναν άλλο (κύριο) τομέα. Οι υποτομείς εμφανίζονται ως νέα ενότητα της διεύθυνσης URL του τομέα σας στο παρελθόντο κύριο URL τομέα.

Πιο συγκεκριμένα:

  • Ο κύριος τομέας μου είναι: //nickmccullum.com
  • Ο νέος τομέας μαθημάτων μου είναι: //courses.nickmccullum.com

Το κύριο πλεονέκτημα ενός υποτομέα είναι ότι είναι δωρεάν! Για να μην αναφέρουμε, ένας υποτομέας που έχει επισημανθεί σε έναν ήδη καταξιωμένο ιστότοπο ευρετηριάζεται γρήγορα και ωφελείται από την επιτυχία του γονέα του.

Ήξερα ότι θα χρειαζόμουν διακομιστή για να φιλοξενήσω τον νέο μου ιστότοπο. Θα ήθελα επίσης να επισυνάψω αυτόν τον διακομιστή με μια ελαστική διεύθυνση IP.

Μια ελαστική διεύθυνση IP είναι μια στατική IP που δεν θα αλλάξει ποτέ. Αυτό σημαίνει ότι μπορεί να έχει πρόσβαση από το κοινό 24/7.

Ο γρηγορότερος τρόπος για να ενεργοποιήσετε και να εκτελέσετε έναν διακομιστή σήμερα είναι να τον φιλοξενήσετε στο cloud. Υπάρχουν πολλές επιλογές για υπολογιστικούς νέφους, όπως το AWS του Amazon, τα σταγονίδια DigitalOcean ή τα κοντέινερ του Azure. Όσον αφορά την τιμολόγηση, οι διαθέσιμες επιλογές είναι σχεδόν ίσες σε όλα τα επίπεδα - οπότε δεν έπαιρνα πάρα πολύ μεγάλη σημασία στην απόφασή μου.

Είχα προηγούμενη εμπειρία με το AWS (Amazon Web Services) - μια υπηρεσία που βασίζεται σε σύννεφο για φιλοξενία υποδομής. Φυσικά επέλεξα να φιλοξενήσω τον διακομιστή μου εδώ. Για να είμαι πιο συγκεκριμένος, φιλοξενώ τον ιστότοπο σε μια παρουσία EC2. Θα μιλήσουμε περισσότερο για αυτό αργότερα.

Εντάξει, οπότε τώρα ήξερα πού ήθελα να φιλοξενήσω τη νέα μου ιστοσελίδα, τι θα ακολουθήσει;

Ήρθε η ώρα να σκεφτούμε την τεχνολογική στοίβα του ιστότοπου. Όταν σκέφτεστε ποια τεχνολογία θα χρησιμοποιήσετε για τη δημιουργία του ιστότοπού σας, είναι σημαντικό να λάβετε υπόψη αυτά τα σημαντικά θέματα:

  1. Σε τι είστε ικανοί
  2. Επιλέγοντας τεχνολογίες frontend και backend που συνδυάζονται καλά
  3. Η απόδοση του ιστότοπου

Πρέπει να απαντήσετε σε αυτές τις ερωτήσεις και να προσπαθήσετε να επιλέξετε μια στοίβα τεχνολογίας που να ταιριάζει στις ανάγκες και τις ικανότητές σας. Για μένα, είμαι πιο ικανός στο Python, οπότε το Django 3.0 ήταν μια φυσική επιλογή!

Είχα εργαστεί σε μια εφαρμογή Django στο παρελθόν (Passiv), οπότε ήμουν σε γενικές γραμμές εξοικειωμένος με την υποδομή. Ωστόσο, δεν είχα χτίσει ποτέ ένα έργο Django από το μηδέν.

Εξαιτίας αυτού, έπρεπε να κάνω κάποια ανάγνωση. Καθώς έμαθα περισσότερα για αυτό το δημοφιλές πλαίσιο συνέχισα να το συγκρίνω με το PHP, το δημοφιλές εργαλείο προγραμματισμού Ιστού. Έχω εργαστεί σε πολλούς ιστότοπους Wordpress στο παρελθόν και το Wordpress βασίζεται σε PHP, οπότε αυτή ήταν μια φυσική σύγκριση (τουλάχιστον για μένα).

Σύμφωνα με την τεκμηρίωσή τους και τις διάφορες δημοσιεύσεις για το Stackoverflow, εδώ είναι οι κύριες διαφορές μεταξύ του πλαισίου Django και των μεγάλων πλαισίων PHP:

  • Το Django επικεντρώνεται περισσότερο στην ασφάλεια από προεπιλογή και παρέχει ενσωματωμένες πρακτικές ασφαλείας για να βοηθήσει τους προγραμματιστές να εξοικονομήσουν χρόνο κατά τη διάρκεια της ανάπτυξης.
  • Το Django επικεντρώνεται στην ταχύτητα. Είναι γνωστό ως ένα πλαίσιο που βοηθά τους προγραμματιστές να ξεκουραστούν το συντομότερο δυνατό.
  • Το Django έχει οριακά χαμηλότερη απόδοση σε σύγκριση με τα περισσότερα πλαίσια που βασίζονται σε PHP.

Θα ήθελα να θίξω αυτό το τελευταίο σημείο. Η Python είναι μια ερμηνευμένη γλώσσα και συνήθως σχετίζεται με χαμηλότερη απόδοση από άλλες γλώσσες προγραμματισμού. Όταν ένας νέος προγραμματιστής ακούει κάτι τέτοιο, μπορεί να πιστεύουν ότι η Python είναι πολύ χειρότερη από άλλες γλωσσικές επιλογές, λόγω της σημασίας της απόδοσης στον υπολογιστή.

Αν και η Python έχει χαμηλότερα πρότυπα απόδοσης σε σύγκριση με άλλες γλώσσες, αυτή είναι μια εξαιρετικά ασαφής δήλωση. Στην πραγματικότητα, η διαφορά μεταξύ Django και Laravel (ένα δημοφιλές πλαίσιο με βάση την PHP) είναι τόσο μικρή που θεωρείται αμελητέα.

Για να σας ενδιαφέρει αυτή η διαφορά απόδοσης, θα πρέπει να συντάσσετε μια εφαρμογή που εξαρτάται σε μεγάλο βαθμό από την απόδοση με εκατομμύρια χρήστες. Με ενθάρρυναν να μάθω ότι πολλές από τις μεγαλύτερες διαδικτυακές εφαρμογές στον κόσμο είναι κατασκευασμένες στο Django. Είπε διαφορετικά, αν το Django είναι αρκετά καλό για το Instagram, τότε ήταν σίγουρα αρκετά καλό για τον ιστότοπό μου.

Στο τέλος αποφάσισα να φτιάξω την ιστοσελίδα των μαθημάτων μου χρησιμοποιώντας το Django κυρίως επειδή έχω εμπειρία με την Python. Η εκμάθηση ενός νέου πλαισίου ιστού ήταν ένα καλό μπόνους.

Στη συνέχεια, ήξερα ότι θα χρειαζόμουν μια βάση δεδομένων για αυτόν τον ιστότοπο. Έχοντας εμπειρία με το MySQL και το PostgreSQL, αρχικά επρόκειτο να το χρησιμοποιήσω ξανά εδώ. Ωστόσο, το Django αποστέλλει προεπιλογή με μια υπηρεσία βάσης δεδομένων SQLite3 που απαιτεί ελάχιστη εγκατάσταση. Δεν έχω χρησιμοποιήσει ποτέ το SQLite, οπότε έκανα ακόμη περισσότερη έρευνα.

Με βάση τις επιδόσεις και τις ανάγκες αποθήκευσης δεδομένων, η προεπιλεγμένη βάση δεδομένων SQLite3 που αποστέλλεται με το Django θα ήταν αρκετά πιο ισχυρή για τον ιστότοπό μου. Ήμουν σοκαρισμένος όταν διαπίστωσα ότι μια ελαφρύτερη έκδοση μιας υπηρεσίας βάσης δεδομένων θα μπορούσε να είναι τόσο ισχυρή!

Για όσους δεν είναι εξοικειωμένοι με αυτήν την τεχνολογία (όπως ήμουν), το SQLite3 είναι μια σχεσιακή βάση δεδομένων με εξαιρετική απόδοση για ιστότοπους με χαμηλά έως μεσαία επίπεδα επισκεψιμότητας (~ 100K επισκέψεις ανά ημέρα). Το SQLite3 μπορεί να εκτελεστεί στον ίδιο διακομιστή με τον ιστότοπο χωρίς να επηρεάζεται η απόδοση. Αυτό σημαίνει ότι δεν χρειάστηκε να δημιουργήσω μια ξεχωριστή παρουσία του Amazon RDS, η οποία εξοικονομεί χρήματα στο στάδιο της ανάπτυξης.

Ξεκινώντας ένα έργο Django

Django is a high-level python web framework with the main goal of allowing rapid development and providing security by default. It takes care of many hassles of web development, reducing repetitive coding practices.

One of the best parts of using Django is that it is absolutely free.

Django is designed to help developers get their websites off the ground quickly (which is one of the main reasons I chose to use it for this project). One of my favourite features of this framework (as with most others) is their frontend templating system.

Django Templates allow you to write dynamic code which then generates the desired HTML and CSS. This gives you the ability to use structures such as loops and if statements in order to create dynamic HTML code (meaning it renders differently for each user) that can then be served as a static file.

For example:

# course_titles_template.html {% for course in courses_list %} 

{{ course.course_title }}

{% endfor %}

Would create a heading for every course variable found in the courses_list object. This could would render an HTML file with an

tag that contains the title of each course, like this:

Python Fundamentals

Advanced Python for Finance and Data Science

How to Run Python Scripts

How to Make A Python Class

The templating system saves you from a lot of manual labor. Allowing the HTML to render dynamically saves you the headaches of updating your code every time you add a new object.

This templating system also allows the web app to update over time as I add more content. So in this case if I were to add a new course to my database, this template would not need to be changed. It would simply render my new course’s title in a new heading tag.

Django also makes it extremely easy to get started in a project. Once you have Django installed, you are able to use the django-admin in order to start a project and even set up your apps.

Hang on a second, apps? Projects? What’s the difference?

An app is a web application that performs some functionality. It can be a blog, a login system, or even a file server. A project is a collection of apps and configurations which together form a website.

Installing Django:

The simplest way to install is with pip, the Python package manager.

python -m pip install Django

Για έναν πλήρη οδηγό εγκατάστασης, ανατρέξτε στην Επίσημη τεκμηρίωση του Django.

Έναρξη έργου:

Μόλις εγκαταστήσετε το Django, θα έχετε πρόσβαση στο django-adminεργαλείο που βοηθά τους προγραμματιστές να ρυθμίζουν έργα και εφαρμογές και επίσης παρέχει άλλα εύχρηστα εργαλεία.

Η εκτέλεση   django-admin startproject myprojectθα δημιουργήσει έναν νέο φάκελο στον τρέχοντα κατάλογο όπου θα ζει το έργο σας. Θα δημιουργήσει επίσης πολλά από τα απαραίτητα αρχεία που θα πρέπει να ξεκινήσετε.

Δείτε πώς θα εμφανίζεται ο κατάλογός σας μετά την εκτέλεση αυτής της εντολής:

το προτζεκτ μου/

   management.py

   το προτζεκτ μου/

       __init__.py

       settings.py

       urls.py

       asgi.py

       wsgi.py

Inside the myproject folder you will find a manage.py file, which is extremely useful and provides many handy utilities. There will be another folder named myproject which will be where you set your configurations for the project.

The outer myproject/ root directory is a container for your project, its name doesn’t actually matter and if you find this confusing you can rename it to anything you like.

The inner myproject/ directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it.

The important files to note here are the myproject/settings.py, where your Django and app specific settings are configured, and the myproject/urls.py.

The urls.py file is used to create urls within your website and point them to a location to service the request. This image does a great job explaining how Django handles requests:

Kudos to Ryan Nevius for creating such a wonderful visualization.

The myproject/urls.py file outlines the URL resolution for the entire website. Each app you add to your website will contain its own urls.py file which outlines the URL resolution within that specific app.

Now that you have a grasp on what some of those files are used for, let’s dive into getting a project started with the manager script’s commands.

Μια εντολή που πρέπει να σημειωθεί είναι η startappεντολή που χρησιμοποιείται για τη δημιουργία μιας εφαρμογής στο έργο σας με τον ίδιο τρόπο που δημιουργήσατε την εφαρμογή. python manage.py startapp myappθα δημιουργήσει έναν νέο φάκελο και μερικά από τα απαραίτητα αρχεία για τη δημιουργία μιας νέας εφαρμογής στο έργο σας.

myapp /  

   __init__.py

   admin.py

   apps.py

   μεταναστευσεις /

       __init__.py

   models.py

   tests.py

   views.py

Η κύρια διαφορά εδώ είναι η παρουσία των μοντέλων και των αρχείων προβολών, τα οποία χρησιμοποιούνται για τον καθορισμό της βάσης δεδομένων και της λειτουργικότητας της εφαρμογής, αντίστοιχα.

Τα μοντέλα είναι τάξεις που καθορίζουν τους πίνακες βάσης δεδομένων σας. Θα συζητήσουμε τα μοντέλα με περισσότερες λεπτομέρειες αργότερα σε αυτό το σεμινάριο.

Οι προβολές ελέγχουν τη δομή και τη λειτουργικότητα της διεπαφής της εφαρμογής λαμβάνοντας ένα αίτημα ιστού και επιστρέφοντας μια απάντηση στον ιστό

Πιθανώς η πιο σημαντική εντολή που πρέπει να θυμάστε είναι η εντολή runerver:

python manage.py runserver. This will run your project on your localhost at the default port, 8000.

That’s it! With three simple steps you will see a welcome landing page showing you that the installation worked.

There is an extremely well written tutorial in Django’s Documentation providing a far more in depth walk through of starting a project. It can be found here: Starting a Project

How to set up models

Like many other web frameworks, Django has an implementation of the object-relational mapping (ORM) concept. In Django, this implementation is called models.

Models are a very important topic to understand when developing a project in Django. In there most basic form, models can be thought of as wrappers for database tables.

Said differently, a Django model is used to define your data. It contains the fields and behaviours of the data you store. Each model maps to a single table in your database and fields in your model map to fields in your database.

When writing models you have access to powerful built-in field types that do a lot of the heavy lifting for you. Forget writing SQL code manually to construct your database. You can simply write a model class and run the migration commands to have a fully functional SQL script loaded into your database.

Django offers a User Model as part of its built in authentication system which allows you to ignore the backend side of all the login/sign-up and password handling.

When designing the models for my new site I needed the following three models:

  • Profile - a wrapper class around the User model to add non-auth related information (often called a Profile Model)
  • Course - to store all the information about each course
  • Document - a model that stores information about which files are attributed to each course. I specifically wanted to upload Markdown documents, as that's how my public blog is already built

Here's an example of a model:

class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) enrolled_courses = models.ManyToManyField(Course)

A Profile Model is a useful tool for extending the functionality of the existing user model in order to store information about the user, beyond just authentication data. In my case I created a profile model named Profile to store which courses the user is enrolled in.

Here's my Course Model:

class Course(models.Model): course_title = models.CharField(max_length=200) course_description = models.CharField(max_length=500) course_price = models.DecimalField(max_digits=10, decimal_places=2)

My Course model is fairly straightforward. I only needed to store 3 pieces of information about each course for logistics while the actual content of the course is handled by the Document model.

class Document(models.Model): course = models.ForeignKey(Course,on_delete=models.PROTECT) file = models.FileField ( upload_to=markdown_upload_location, default="default.md" )

Here I take advantage of some built in python functionality, where I’m passing the function markdown_upload_location into the FileField constructor.

This function is used to determine where the file being uploaded is to be stored on the file system. Passing the function into the constructor allows the function to be run each time a new file is uploaded instead of only being run once and then the same result being used over again.

Essentially, when an admin (me) uploads a new course to the site, a new folder is created for that course and all markdown files for that course are stored there. The Document model records link those files to the course record in the database.

One thing I took away from setting up these models was how easy the process of designing my database became. Gone are the days of MySQL Workbench and ERR diagrams, or writing SQL line-by-line and executing painful updates to schemas.

Integrating Stripe Payments

Stripe is a platform used by many websites around the world to take payment from customers. It’s secure, easy to use for customers and most importantly, it’s easy for us developers to set up!

The pricing is also quite fair compared to their competition, currently sitting at 2.9% + 0.30 CAD per transaction. This pricing applies to one time payments as well as their subscription sign ups.

In order to use Stripe as a developer you must make an account and check out their developer pages to review the options. They have prebuilt checkouts, entire libraries and SDKs for building your own custom checkout. Stripe also provides preexisting plugins for web frameworks (Wordpress, Drupal, etc.)

I decided to use their Checkout tool which is a secure, Stripe-hosted payment page that allowed me to avoid having to build a payment page. This not only saves the time of developing the frontend page for collecting payment information, but also the hassle of securing the payment in the backend.

Security is a huge topic nowadays and customers are wary of where they hand out their credit card details, so for me, using Stripe was a no brainer. I store none of the users details. Instead, they are sent straight to Stripe where they can be securely handled.

With a few lines of code I was able to import Stripe’s pre-built Javascript checkout module. Here's the script tag:

Here the data-key is set to the Stripe public key, similar to any developer API key. The description is what will appear in your Stripe dashboard for the payment received and the amount is the number of cents for the purchase. This simple inclusion imports this payment page as a modal on the website:

Once a customer fills out the payment information you only need to bundle up the payment information into a request and send it to Stripe. Next, Stripe is able to process the information and approve the payment within seconds.

# Send the charge to Stripe charge = stripe.Charge.create( amount=amount, currency=currency, description=f"Payment for course: {courseTitle}", source=self.request.POST['stripeToken'] )

Deploying my new site on an EC2 instance

Once I was finished developing my new site on my localhost, I needed to find a place to deploy it. I’ve had some experience with AWS and already had an account so it made for an easy decision.

Amazon’s Elastic Compute Cloud - usually referred to as EC2 - allows for an abundance of configurations, I simply went with the most straightforward set up. More specifically, a Ubuntu machine running on a T2 Micro server would be ample performance for this site.

Setting up the server was the easiest part of deployment, I set up a server in less than 10 minutes. Next I had to attach an elastic IP address to the instance and update my DNS records in Route53 (where my domain lives).

After setting up the server I had to figure out how I was going to serve the website to visitors. I’ve had some experience in the past with Apache so that was a natural choice. It turns out that Apache and Django mesh together very well.

Django is served via its WSGI (Web Server Gateway Interface) - a fast CGI interface for Python, this is similar to PHP’s FPM if you are familiar with that. In simple terms, the WSGI is a layer between Django and the web server that acts as an interface to serve the web pages.

As you may already know, Python is normally run within a virtualenv. This creates a virtual environment where the dependencies for a particular project can live without interfering with the system’s version of python.

If you’d like to learn a bit more about virtualenv check out the Hitchhiker's Guide to Python.

Basically this is important only to configure the Apache configurations. To serve the files correctly you need to make a WSGI Daemon for your Django project like so:

# /etc/apache2/sites-available/mysite.conf: WSGIProcessGroup courses.nickmccullum.com WSGIDaemonProcess course python-path=/home/ubuntu/django/courses-website python-home=/home/ubuntu/django/courses-website-venv WSGIProcessGroup course WSGIScriptAlias / /home/ubuntu/django/courses-website/courses-website/wsgi.py  ServerName courses.nickmccullum.com 

This tells Apache to utilize the WSGI daemon in order to properly serve the files from the Django project. Once this was set up, I needed to restart Apache, wait the 24 hours it took for the DNS records to update, then - voilà:

One last step, I needed to secure my site with SSL (Secure Socket Layer). After all, I am asking people to make payments on my site, so customers will expect the site to be secured!

The simplest way to enable SSL on a site, in my opinion, is through Lets Encrypt. They offer a tool called Certbot for free, which can be enabled on your server to auto renew a server certificate and keep your server running with SSL 24/7 all year long.

It’s as simple as the following three steps:

1. Install Certbot:

sudo apt-get install certbot python3-certbot-apache

NOTE: This script will look at the ServerName setting in your apache configuration file to create the certificate so make sure you’ve set that before running it.

2. Get the certificate and tell certbot to update the apache configuration automatically:

sudo certbot --apache

3. Test the auto renewal:

sudo certbot renew --dry-run

Once you’ve configured SSL you can test to make sure the certificate was installed correctly by checking this website: //www.ssllabs.com/ssltest/.

After securing my site with SSL I opened the EC2 instance’s security rules to allow the site to be public. With my new site up and running on my EC2 instance, I am now able to securely sell my courses to customers who wish to learn about various topics in software development.

Final Thoughts

I am grateful for all of the experience I gained throughout this project, from navigating a new web framework to integrating the Stripe API – I certainly learned a lot!

Learning a new topic like Django can be overwhelming but I felt their documentation was very strong compared to others that I’ve read (erhm, AWS).

Αν επρόκειτο να δώσω μια συμβουλή, θα σας έλεγα ότι ο πιο πολύτιμος πόρος με οποιοδήποτε εργαλείο είναι η επίσημη τεκμηρίωση. Αυτό ισχύει ιδιαίτερα όταν είναι καλά γραμμένο. Όμως, ανεξάρτητα από το εργαλείο που χρησιμοποιείτε, μην φοβάστε ποτέ τα έγγραφα και συνηθίστε να τα διαβάζετε για να βρείτε απαντήσεις στα προβλήματά σας.

Αυτό το άρθρο γράφτηκε από τον Nick McCullum, ο οποίος διδάσκει μαθήματα Python, JavaScript και Data Science στον ιστότοπό του.