اطلاعیه شماره 26 : به اطلاع کلیه کاربران وبسایت پایتونی ها می رساند به علت تداخلات شدید و محدودیت ها موجود در اینترنت کشور سرور های پایتونی ها با اختلال رو به رو شده که همکاران واحد فنی در حال بررسی موضوع هستند تا هرچه سریعتر مشکل را مرتفع کنند، لطفا صبور باشید.

021-71053903 [email protected] پشتیبانی از شنبه تا چهارشنبه ساعت 9 الی 16

چگونه در جنگو Stripe SaaS بسازیم

چگونه در جنگو Stripe SaaS بسازیم

مقدمه

با سلام خدمت تمامی مخاطبین خوب وبسایت پایتونی ها با یک مقاله آموزشی از سری مقالات جنگو در خدمت شما بزرگواران هستیم تا در این مقاله با استفاده از جنگو و Strip یک قالب بر مبنای Saas طراحی کنیم.

بیایید با استفاده از Django و Stripe یک قالب SaaS بسازیم. با پروژه boilerplate، می توانید به سرعت حداقل محصول قابل دوام خود را به جای چند هفته در چند روز بسازید.

ما از Django برای Backend و Stripe برای جمع آوری پرداخت های ماهانه استفاده می کنیم.

 

 

مشکلات و راه حل ها را شناسایی کنید

اولین و مهم ترین قضیه این است که برای شروع، به یک ایده نیاز دارید.

ایده های تصادفی کاملا عالی است، اما هنگام یافتن یک ایده SaaS مفید نیست چون ممکن است شما را گمراه کند.

با شناسایی مشکلات در هر جامعه ای از مردم یا صنعت تجاری شروع کنید.

چرا باید مشکلات را شناسایی کنیم؟

زیرا حل مشکلات به این معنی است که می توانید برای ارائه راه حل پول دریافت کنید.

اگر نرم افزار شما مشکلی را در صنعت آنها حل کند، شرکت ها با کمال میل هزینه راه حل را به صورت مکرر پرداخت می کنند.

 

3 مطالعه موردی SaaS سریع: مشکلات و راه حل ها

کانوا

  • مخاطب : افراد، تیم های کوچک و شرکت ها
  • مشکل : استفاده از برنامه های طراحی گرافیک ساده نیست و به فردی با تجربه در طراحی گرافیک نیاز دارد.
  • راه حل : یک پلت فرم کشیدن و رها کردن برای طراحی گرافیکی که هر کسی می تواند از آن استفاده کند.

WebFlow

  • مخاطب : توسعه دهندگان وب و غیر برنامه نویسان
  • مشکل : کدنویسی یک وب سایت ماه ها طول می کشد.
  • راه حل : یک پلت فرم بدون کد برای توسعه وب.

MailChimp

  • مخاطب : مشاغل کوچک
  • مشکل : اجرای یک کمپین بازاریابی ایمیلی زمان بر است.
  • راه حل : ایمیل های خودکار را برنامه ریزی کنید و نتایج را پیگیری کنید.

Boilerplate را برای SaaS خود ایجاد کنید

مثال مشکل و راه حل SaaS

بنابراین، فرض کنید مشکلی را شناسایی کرده‌ایم – کسب‌وکارهای کوچک پلت‌فرم ساده‌ای برای نظارت بر هزینه‌های ماهانه خود ندارند. اکسل وجود دارد اما استفاده از آن نیاز به دانش قبلی دارد .

راه حل ما ارائه نرم افزاری است که در آن کاربران برای داشتن یک داشبورد ساده که به آنها امکان می دهد هزینه های ماهانه خود را مدیریت کنند، پول پرداخت می کنند.

حال به خاطر داشته باشید که این فقط یک مثال است. در حال حاضر شرکت هایی وجود دارند که نرم افزار حسابداری را برای مشاغل کوچک ارائه می دهند. اگر بتوانیم ارزش پیشنهادی بهتری ارائه دهیم، استفاده از آن را آسان‌تر کنیم و مخاطبان مناسبی را هدف قرار دهیم، می‌توانیم متناسب با بازار محصول را پیدا کنیم.

ما اسکلت یک MVP را برای تأیید اعتبار محصول و جمع‌آوری بازخورد بدون صرف زمان یا هزینه زیاد برای محصول می‌سازیم.

به این ترتیب تنها با افزودن عملکرد اصلی می توانیم به سرعت برای توسعه حرکت کنیم.

اکنون بیایید شروع به ساخت یک محصول حداقل قابل دوام (MVP) کنیم.

 

جنگو را نصب کنید

خط فرمان ویندوز

C:\Users\Owner\desktop> py -m venv env

C:\Users\Owner\desktop> cd env

C:\Users\Owner\desktop\env> Scripts\activate

(env)C:\Users\Owner\desktop\env>pip install django

(env)C:\Users\Owner\desktop\env>django-admin startproject mysite

(env)C:\Users\Owner\desktop\env> cd mysite

(env)C:\Users\Owner\desktop\env\mysite> py manage.py startapp main

(env) C:\Users\Owner\Desktop\Code\env\mysite>py manage.py runserver

 

یک محیط مجازی بسازید و جنگو را نصب کنید. محیط مجازی یک محیط ایزوله برای بسته های خاص پروژه ایجاد می کند. جنگو چارچوبی است که پایگاه داده، احراز هویت کاربر و موتورهای قالب را کنترل می کند.

 

 

Django Crispy Forms را نصب کنید

خط فرمان ویندوز

(env)C:\Users\Owner\desktop\env>pip install django-crispy-forms

Django Crispy Forms را نصب کنید . ما از این بسته برای استایل دادن به فرم‌های جنگو که برای ثبت نام و ورود کاربر استفاده می‌شوند، استفاده می‌کنیم.

 

جنگو را پیکربندی کنید

env > mysite > mysite > settings.py

...

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'main',
    'crispy_forms',
]

CRISPY_TEMPLATE_PACK = 'bootstrap4'
...


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    BASE_DIR / "static",
    '/var/www/static/',
]

...

MESSAGE_TAGS = {
        messages.DEBUG: 'alert-secondary',
        messages.INFO: 'alert-info',
        messages.SUCCESS: 'alert-success',
        messages.WARNING: 'alert-warning',
        messages.ERROR: 'alert-danger',
 }

اکنون باید تنظیمات اولیه جنگو را به فایل تنظیمات خود اضافه کنید. mainبه لیست برنامه های نصب شده اضافه crispy_formsکنید، بسته قالب Crispy forms را اضافه کنید و پروژه را برای فایل های ثابت پیکربندی کنید .

همچنین، چارچوب پیام های جنگو را با هشدارهای بوت استرپ پیکربندی کنید .

 

 

یک صفحه StyleSheet اضافه کنید

env > mysite >  (New Folder) static >  (New Folder) main >  (New Folder) css

/*client images */
 .client {
   height:60px; 
   width:60px; 
   border-radius: 50%; 
   object-fit:cover;
 }

 /*quote svgs*/
 .bi-chat-square-quote{
   color:rgb(108,99,255, 0.3);
 }

 /*badge color*/
 .badge{
   background-color:rgb(108,99,255, 0.2) !important;
   color:rgb(108,99,255) !important;
 }

 /*stars color */
 .bi-star, .bi-star-fill, .bi-star-half{
   color:#ffc107;
 }

 /* cta text*/
 .cta{
   font-size: 70px;
   line-height: 75px;
   font-family: 'Roboto Slab', serif;
 }


 .navbar-brand{
   font-family: 'Roboto Slab', serif;
 }

 .cta-span{
   color:rgb(108,99,255, 0.8) !important;
 }

 .bg-primary{
   background:rgb(108,99,255) !important;
 }

 .border-primary {
   border: 1px solid rgb(108,99,255) !important;
 }


 .btn-primary, .btn-primary:visited {
     font-weight:600;
     background: rgb(255,86,120);
     border: 1px solid rgb(255,86,120);
     color: white !important;
     border-radius:0px;
 }
 
 .btn-primary:hover, .btn-primary:active, .btn-primary:focus, 
 .btn-outline-primary:hover, .btn-outline-primary:active, .btn-outline-primary:focus {
    background: rgb(255,61,100) !important;
    border: 1px solid rgb(255,61,100) !important;
    border-radius:0px;
    color:white !important;
 }

 .btn-outline-primary, .btn-outline-primary:visited {
     font-weight:600;
     background: transparent;
     border: 1px solid rgb(255,86,120);
     color: rgb(255,61,100);
     border-radius:0px;
 }
 
 .form-control{
   background:#F2F2F2;
   border-radius:0px;
   border:none;
   height:48px !important;
 }

 /*background circle for icons*/
 .numberCircle {
   border-radius: 50%;
   width: 60px;
   height: 60px;
   padding: 8px;
   background:rgb(255,86,120, 0.2);
   border: none;
   color: rgb(255,86,120);
   text-align: center;
   font-size: 25px;
 }

 p{
   line-height: 25px;
 }

 .nav-pills .nav-link.active, .nav-pills .show>.nav-link {
 color: #fff !important;
 background-color:rgb(138,131,255);
 }

 .nav-link:hover{
   color: rgb(138,131,255) !important;
 }

 .footer-social-link:hover {
   color:rgb(137,130,255) !important;
 }

 @media only screen and (max-width: 600px) {  
     .cta{
       font-size: 50px;
       line-height: 55px;
       font-family: 'Roboto Slab', serif;
     }

  }

 @media only screen and (max-width:768px){
   /*background circle for icons*/
     .numberCircle {
       border-radius: 50%;
       width: 60px;
       height: 60px;
       padding: 8px;
       background:rgb(255,86,120, 0.2);
       border: none;
       color: rgb(255,86,120);
       text-align: center;
       font-size: 25px;
       margin-left: auto;
       margin-right: auto;
     }
 }

 

 

یک شیوه نامه سفارشی به پروژه اضافه کنید

تصاویر را اضافه کنید

env > mysite >  (New Folder)  static >  (New Folder)  main >  (New Folder)  img

تصاویر را به پروژه اضافه کنید. با خیال راحت از تصاویر خود استفاده کنید یا تصویر منبع باز را که در opendoodles.com استفاده کردم، بررسی کنید .

 

یک Menu ایجاد کنید

env > mysite > main > templates > main > (New Folder) شامل > (New File) navbar.html

<nav class="navbar navbar-expand-lg navbar-light bg-transparent">
  <div class="container-fluid">
    <a class="navbar-brand" href="/">
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="color: rgb(137,130,255);" fill="currentColor" class="bi bi-bar-chart-fill" viewBox="0 0 16 16">
        <path d="M1 11a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-3zm5-4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7zm5-5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V2z"/>
      </svg>
      Track Smart
    </a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="False" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
      {% if user.is_authenticated %}
        <li class="nav-item">
          <a class="nav-link" href="/dashboard">Dashboard</a>
        </li>
         <li class="nav-item">
          <a class="nav-link" href="/logout">Logout</a>
        </li>
         {% else %}
        <li class="nav-item">
          <a class="nav-link" href="#">Features</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="/pricing">Pricing</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="/login">Login</a>
        </li>
      {% endif %}
      </ul>
      {% if user.is_authenticated %}
        <p>Welcome, {{user.username}}</p>
      {% else %}
        <a href="/register" class="btn btn-outline-primary" type="button">Get Started</a>
      {% endif %}
    </div>
  </div>
</nav>

در اینجا یک نوار ناوبری با جنگو در صورت وجود شرایط موجود در قالب وجود دارد. من دو شرط if دارم که هر دوی آنها متن و پیوندهای متفاوتی را به کاربر تایید شده نسبت به کاربر غیرثبت شده نشان می دهد.

 

یک Footer ایجاد کنید

env > mysite > main > templates > main > (New Folder) شامل >  (New File) footer.html

<div class="container-fluid text-center p-5">
    <div class='row'>
        <div class='col-lg-6 col-md-12 text-center text-md-left'>
            <p>© Company</p>
        </div>
        <div class='col-lg-6 col-md-12 text-center text-md-left'>
            <a href="#" class="text-dark footer-social-link"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="mx-2" fill="currentColor" class="bi bi-facebook" viewBox="0 0 16 16">
                <path d="M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951z"/>
            </svg></a>
            <a href="#" class="text-dark footer-social-link"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="mx-2" fill="currentColor" class="bi bi-instagram" viewBox="0 0 16 16">
                <path d="M8 0C5.829 0 5.556.01 4.703.048 3.85.088 3.269.222 2.76.42a3.917 3.917 0 0 0-1.417.923A3.927 3.927 0 0 0 .42 2.76C.222 3.268.087 3.85.048 4.7.01 5.555 0 5.827 0 8.001c0 2.172.01 2.444.048 3.297.04.852.174 1.433.372 1.942.205.526.478.972.923 1.417.444.445.89.719 1.416.923.51.198 1.09.333 1.942.372C5.555 15.99 5.827 16 8 16s2.444-.01 3.298-.048c.851-.04 1.434-.174 1.943-.372a3.916 3.916 0 0 0 1.416-.923c.445-.445.718-.891.923-1.417.197-.509.332-1.09.372-1.942C15.99 10.445 16 10.173 16 8s-.01-2.445-.048-3.299c-.04-.851-.175-1.433-.372-1.941a3.926 3.926 0 0 0-.923-1.417A3.911 3.911 0 0 0 13.24.42c-.51-.198-1.092-.333-1.943-.372C10.443.01 10.172 0 7.998 0h.003zm-.717 1.442h.718c2.136 0 2.389.007 3.232.046.78.035 1.204.166 1.486.275.373.145.64.319.92.599.28.28.453.546.598.92.11.281.24.705.275 1.485.039.843.047 1.096.047 3.231s-.008 2.389-.047 3.232c-.035.78-.166 1.203-.275 1.485a2.47 2.47 0 0 1-.599.919c-.28.28-.546.453-.92.598-.28.11-.704.24-1.485.276-.843.038-1.096.047-3.232.047s-2.39-.009-3.233-.047c-.78-.036-1.203-.166-1.485-.276a2.478 2.478 0 0 1-.92-.598 2.48 2.48 0 0 1-.6-.92c-.109-.281-.24-.705-.275-1.485-.038-.843-.046-1.096-.046-3.233 0-2.136.008-2.388.046-3.231.036-.78.166-1.204.276-1.486.145-.373.319-.64.599-.92.28-.28.546-.453.92-.598.282-.11.705-.24 1.485-.276.738-.034 1.024-.044 2.515-.045v.002zm4.988 1.328a.96.96 0 1 0 0 1.92.96.96 0 0 0 0-1.92zm-4.27 1.122a4.109 4.109 0 1 0 0 8.217 4.109 4.109 0 0 0 0-8.217zm0 1.441a2.667 2.667 0 1 1 0 5.334 2.667 2.667 0 0 1 0-5.334z"/>
            </svg></a>
            <a href="#" class="text-dark footer-social-link"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="mx-2" fill="currentColor" class="bi bi-twitter" viewBox="0 0 16 16">
                <path d="M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z"/>
            </svg></a>

        </div>
    </div>
    
</div>

 

 

یک header.html جنگو ایجاد کنید

env > mysite > main > templates > main > (New File) header.html

<!DOCTYPE html>
<html lang="en">
<head>
    {% load static %}
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">

    <!--Custom CSS-->
    <link rel="stylesheet" href="{% static 'main/css/stylesheet.css'%}" type="text/css">

    <!--Google Fonts-->
    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:[email protected]&display=swap" rel="stylesheet">

    <title>Django + Stripe SaaS</title>
</head>
<body>
    {% include "main/includes/navbar.html" %}

    {% include 'main/includes/messages.html' %}

    <div class="my-5">
        {% block content %}

        {% endblock %} 
    </div>

    {% include 'main/includes/footer.html' %}

    <!-- Optional JavaScript; choose one of the two! -->

    <!-- Option 1: Bootstrap Bundle with Popper -->
    <script class="lazy" data-class="lazy" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4" crossorigin="anonymous"></script>
</body>
</html>

این هدر است که به سایر قالب های HTML گسترش می یابد. از تگ های قالب جنگو و گسترش آن استفاده می کند . همچنین حاوی CDN های Bootstrap است.

 

یک صفحه اصلی ایجاد کنید

env > mysite > main > templates > main > (New File) home.html

{% extends 'main/header.html' %}
{% block content %}
{% load static %}
<!--CTA-->
<div class="container text-center p-lg-5 p-3">
    <div class="row p-lg-5 p-3">
        <div class="col-lg-6 col-md-12 mb-4">
            <h1 class="cta">Track your monthly spending <span class="cta-span">easily.</span></h1>
            <h5 class="text-muted lead my-3">Don't run away from your finances. Jump right in.</h5>
            <form class="my-5" method="GET" action="/register">
                <div class="row">
                    <div class="col-xl-6 col-lg-12 mb-4">
                        <div class="form-floating mb-3">
                            <input type="text" name="email" class="form-control" id="floatingTextInput1" placeholder="[email protected]">
                            <label for="floatingTextInput1">Enter email address...</label>
                        </div>
                    </div>
                    <div class="col-xl-6 col-lg-12">
                        <div class="d-grid">
                            <button class="btn btn-primary btn-lg" type="submit">Join ➜</button>
                        </div>
                    </div>
                </div>
            </form>
        </div>
        <div class="col-lg-6 col-md-12 my-auto">
            <img class="img-fluid" class="lazy" src="{% static 'main/img/jumping.svg' %}" alt="jumping">
        </div>
    </div>
</div>
<!--End CTA-->


<!--Value Prop-->

<div class="container p-lg-5 p-3">
    <div class="row p-lg-5 p-3 my-5">
        <div class="col-lg-6 col-md-12 order-lg-2 order-md-1 my-auto">
            <span class="badge rounded-pill">Track monthly spending</span>
            <h1 class="my-3">Reach your monthly budget</h1>
            <p class="text-muted">Set weekly and monthly spending habits for your entire team. Get alerts when your close to your limit.</p>
        </div>
        <div class="col-lg-6 col-md-12 order-lg-1 order-md-2 my-auto">
            <img class="img-fluid" class="lazy" src="{% static 'main/img/sprinting.gif' %}" alt="sprinting">
        </div>
    </div>
</div>

<div class="container p-lg-5 p-3">
    <div class="row p-lg-5 p-3 my-5">
        <div class="col-lg-6 col-md-12 my-auto">
            <span class="badge rounded-pill">Upload images and PDFs</span>
            <h1 class="my-3">Spending made easy</h1>
            <p class="text-muted">No need to keep physical copies of receipts or bills. Upload your images and PDFs with a click of a button to your account.</p>
        </div>
        <div class="col-lg-6 col-md-12 my-auto">
            <img class="img-fluid" class="lazy" src="{% static 'main/img/clumsy.svg' %}" alt="clumsy">
        </div>
    </div>
</div>
<!--End Value Prop-->



<!--Features-->
<div class="container p-lg-5 p-3 text-center text-md-start">
    <h1 class="cta mt-5 text-center">Healthy spending made easy</h1>
    <h5 class="text-muted lead mt-3 mb-5 text-center">We build a platform designed for small businesses. Track your spending, marketing budget and more all one a simple dashboard.</h5>
    <div class="row p-lg-5 px-3 py-5">
        <div class="col-sm-12 col-md-6 col-lg-3 pb-4">
            <div class="numberCircle my-3">
                <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-phone" viewBox="0 0 16 16">
                    <path d="M11 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h6zM5 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H5z"/>
                    <path d="M8 14a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
                </svg>
            </div>
            <h5 class="card-title">Mobile Friendly</h5>
            <p class="card-text">Monitor your expenses on the go</p>
        </div>
        <div class="col-sm-12 col-md-6 col-lg-3 pb-4"> 
            <div class="numberCircle my-3">
                <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-archive" viewBox="0 0 16 16">
                  <path d="M0 2a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1v7.5a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 1 12.5V5a1 1 0 0 1-1-1V2zm2 3v7.5A1.5 1.5 0 0 0 3.5 14h9a1.5 1.5 0 0 0 1.5-1.5V5H2zm13-3H1v2h14V2zM5 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5z"/>
                </svg>
            </div>
            <h5 class="card-title">Archived Files</h5>
            <p class="card-text">Refer to archived files forever</p>

        </div>
        <div class="col-sm-12 col-md-6 col-lg-3 pb-4">
            <div class="numberCircle my-3">
                <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-bag-plus" viewBox="0 0 16 16">
                  <path fill-rule="evenodd" d="M8 7.5a.5.5 0 0 1 .5.5v1.5H10a.5.5 0 0 1 0 1H8.5V12a.5.5 0 0 1-1 0v-1.5H6a.5.5 0 0 1 0-1h1.5V8a.5.5 0 0 1 .5-.5z"/>
                  <path d="M8 1a2.5 2.5 0 0 1 2.5 2.5V4h-5v-.5A2.5 2.5 0 0 1 8 1zm3.5 3v-.5a3.5 3.5 0 1 0-7 0V4H1v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V4h-3.5zM2 5h12v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5z"/>
                </svg>
            </div>
            <h5 class="card-title">Upload Receipts</h5>
            <p class="card-text">Upload an image of receipt of your purchases</p>

        </div>
        <div class="col-sm-12 col-md-6 col-lg-3 pb-4">
            <div class="numberCircle my-3">
                <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-alarm" viewBox="0 0 16 16">
                  <path d="M8.5 5.5a.5.5 0 0 0-1 0v3.362l-1.429 2.38a.5.5 0 1 0 .858.515l1.5-2.5A.5.5 0 0 0 8.5 9V5.5z"/>
                  <path d="M6.5 0a.5.5 0 0 0 0 1H7v1.07a7.001 7.001 0 0 0-3.273 12.474l-.602.602a.5.5 0 0 0 .707.708l.746-.746A6.97 6.97 0 0 0 8 16a6.97 6.97 0 0 0 3.422-.892l.746.746a.5.5 0 0 0 .707-.708l-.601-.602A7.001 7.001 0 0 0 9 2.07V1h.5a.5.5 0 0 0 0-1h-3zm1.038 3.018a6.093 6.093 0 0 1 .924 0 6 6 0 1 1-.924 0zM0 3.5c0 .753.333 1.429.86 1.887A8.035 8.035 0 0 1 4.387 1.86 2.5 2.5 0 0 0 0 3.5zM13.5 1c-.753 0-1.429.333-1.887.86a8.035 8.035 0 0 1 3.527 3.527A2.5 2.5 0 0 0 13.5 1z"/>
                </svg>
            </div>
            <h5 class="card-title">Set Alerts</h5>
            <p class="card-text">Monitor your spending habits with automatic alerts</p>
        </div>
    </div>
</div>
<!--End Features-->



<!--Value Prop #2-->
<div class="container p-lg-5 p-3">
    <div class="row p-lg-5 p-3 my-5">
        <div class="col-lg-6 col-md-12 order-lg-2 order-md-1 my-auto">
            <span class="badge rounded-pill">Save your time</span>
            <h1 class="my-3">Efficiently allocate time</h1>
            <p class="text-muted">Don't send hours looking over your finances every month. Manage expenses as they happen so you can free up your time.</p>
        </div>
        <div class="col-lg-6 col-md-12 order-lg-1 order-md-2 my-auto">
            <img class="img-fluid" class="lazy" src="{% static 'main/img/sitting-reading.svg' %}" alt="sitting-reading">
        </div>
    </div>
</div>

<div class="container p-lg-5 p-3">
    <div class="row p-lg-5 p-3 my-5">
        <div class="col-lg-6 col-md-12 my-auto">
            <span class="badge rounded-pill">Setup made easy</span>
            <h1>Out of the box configuration</h1>
            <p class="text-muted">Create an account and get going. Everything is already configured for easy file upload and tracking on the dashboard.</p>
        </div>
        <div class="col-lg-6 col-md-12 my-auto">
            <img class="img-fluid" class="lazy" src="{% static 'main/img/unboxing.svg' %}" alt="unboxing">
        </div>
    </div>
</div>
<!--End Value Prop #2-->


<!--Testimonials-->
<div class="container p-lg-5 p-3 text-center text-md-start">
    <div class="row p-lg-5 p-3 my-5">
        <div class="col-lg-6 col-md-12 my-5">
            <svg xmlns="http://www.w3.org/2000/svg" width="3em" height="3em" fill="currentColor" class="my-3 bi bi-chat-square-quote" viewBox="0 0 16 16">
                <path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-2.5a2 2 0 0 0-1.6.8L8 14.333 6.1 11.8a2 2 0 0 0-1.6-.8H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2.5a1 1 0 0 1 .8.4l1.9 2.533a1 1 0 0 0 1.6 0l1.9-2.533a1 1 0 0 1 .8-.4H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
                <path d="M7.066 4.76A1.665 1.665 0 0 0 4 5.668a1.667 1.667 0 0 0 2.561 1.406c-.131.389-.375.804-.777 1.22a.417.417 0 1 0 .6.58c1.486-1.54 1.293-3.214.682-4.112zm4 0A1.665 1.665 0 0 0 8 5.668a1.667 1.667 0 0 0 2.561 1.406c-.131.389-.375.804-.777 1.22a.417.417 0 1 0 .6.58c1.486-1.54 1.293-3.214.682-4.112z"/>
            </svg>
            <figure>
                <blockquote class="blockquote">
                    <p>Great product. Love the easy-to-use interface. Saves my employees at least 2 hours by not having to constantly check up with one another and reference a spreadsheet.</p>
                </blockquote>
                        <img class="lazy" src="{% static 'main/img/ben.png' %}" class="img-fluid client"><br>
                        <b>Ben Smith</b>
                        <br><small>Founder, Clean Paws</small><br>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star" viewBox="0 0 16 16">
                            <path d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957-3.686-1.894a.503.503 0 0 0-.461 0z"/>
                        </svg>
            </figure>
        </div>
        <div class="col-lg-6 col-md-12 my-5">
            <svg xmlns="http://www.w3.org/2000/svg" width="3em" height="3em" fill="currentColor" class="my-3 bi bi-chat-square-quote" viewBox="0 0 16 16">
                <path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-2.5a2 2 0 0 0-1.6.8L8 14.333 6.1 11.8a2 2 0 0 0-1.6-.8H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2.5a1 1 0 0 1 .8.4l1.9 2.533a1 1 0 0 0 1.6 0l1.9-2.533a1 1 0 0 1 .8-.4H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
                <path d="M7.066 4.76A1.665 1.665 0 0 0 4 5.668a1.667 1.667 0 0 0 2.561 1.406c-.131.389-.375.804-.777 1.22a.417.417 0 1 0 .6.58c1.486-1.54 1.293-3.214.682-4.112zm4 0A1.665 1.665 0 0 0 8 5.668a1.667 1.667 0 0 0 2.561 1.406c-.131.389-.375.804-.777 1.22a.417.417 0 1 0 .6.58c1.486-1.54 1.293-3.214.682-4.112z"/>
            </svg>
            <figure>
                <blockquote class="blockquote">
                    <p>I never need to worry about keeping track of receipts or spending. Everything is gets uploaded directly to the site.</p>
                </blockquote>
                        <img class="lazy" src="{% static 'main/img/karen.png' %}" class="img-fluid client"><br>
                        <b>Karen Adams</b>
                        <br><small>Owner, Restaurant Cafe</small><br>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                        </svg>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star" viewBox="0 0 16 16">
                            <path d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957-3.686-1.894a.503.503 0 0 0-.461 0z"/>
                        </svg>   
            </figure>
        </div>
    </div>
</div>
<!--End Testimonials-->


<!--Second CTA-->
<div class="container text-center p-lg-5 p-3">
    <h1 class="cta my-5">Get started today</h1>
    <h5 class="text-muted lead my-4">Stay on top of your small business's finances. Jump right in.</h5>
    <form  method="GET" action="/register">
        <div class="form-floating mb-3 mx-auto" style="max-width: 40rem">
            <input type="text" name="email" class="form-control" id="floatingTextInput1" placeholder="[email protected]">
            <label for="floatingTextInput1">Enter email address...</label>
            <div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
        </div>
        <button class="btn btn-primary btn-lg my-4" type="submit">Join ➜</button>
    </form>
</div>
<!-- End Second CTA-->

{% endblock %}

صفحه اصلی باید شامل یک فراخوان برای اقدام (CTA) در بالای صفحه باشد. به عبارت دیگر، CTA باید در بارگذاری صفحه بدون اسکرول کاربر ظاهر شود.

بعد از CTA گزاره ارزش قرار دارد. ممکن است چندین مورد وجود داشته باشد که مزایای نرم افزار را برجسته می کند. بعد ویژگی ها هستند. اینها نکات برجسته سریعی هستند که جنبه های مفید پلتفرم را به نمایش می گذارند.

بخش دیگری از صفحه اصلی باید توصیفات باشد. هدف برجسته کردن اعتماد موجود بین مشتری فعلی و نرم افزار است. 

در نهایت یک CTA دیگر در پایین صفحه اضافه کنید. به این ترتیب کاربران مجبور نیستند فقط برای ثبت نام به بالای صفحه بروند.

 

 

 

 

یک صفحه ثبت نام ایجاد کنید

env > mysite > main > templates > main > (New File) login.html

{% extends 'main/header.html' %}
    {% block content %}
    {% load crispy_forms_tags %}
    {% load static %}
<div class="container p-md-3 p-sm-2">
    <div class="row g-0">
        <div class="col d-none d-lg-block my-auto">
            <img class="img-fluid" class="lazy" src="{% static 'main/img/sitting-reading.svg' %}" alt="sitting-reading">
        </div>
        <div class="col my-auto">
    <div class="mx-auto" style="max-width:30rem">
    <h1 class="cta my-5 text-center">Register</h1>
    <form method="POST">
        {% csrf_token %}
        {{ register_form|crispy }}                    
        <button class="btn btn-primary my-5" type="submit">Register</button>
    </form>
    </div>
    </div>
</div>
</div>
    {% endblock %}

یک الگوی ثبت نام با فرم ثبت نام اضافه شده به views.py در زیر است اضافه کنید.

برای تنظیم فرم های ثبت نام و ورود به سیستم مورد استفاده در این الگو و فرم زیر  ، به راهنمای ثبت نام کاربر، ورود و خروج از سیستم جنگو بروید .

 

یک صفحه ورود ایجاد کنید

env > mysite > main > templates > main > (New File) login.html

{% extends 'main/header.html' %}
    {% block content %}
    {% load crispy_forms_tags %}
    {% load static %}
<div class="container p-md-3 p-sm-2">
    <div class="row g-0">
        <div class="col d-none d-lg-block my-auto">
            <img class="img-fluid" class="lazy" src="{% static 'main/img/reading-side.svg' %}" alt="reading-side">
        </div>
        <div class="col my-auto">
    <div class="mx-auto" style="max-width:30rem">
    <h1 class="cta my-5 text-center">Login</h1>
    <form method="POST">
        {% csrf_token %}
        {{ login_form|crispy }}                    
        <button class="btn btn-primary my-5" type="submit">Login</button>
        <p class="text-center">Don't have an account? <a href="/register">Create an account</a>.</p>
    </form>
    </div>
    </div>
</div>
</div>
    {% endblock %}

همچنین، یک الگوی ورود به سیستم با یک فرم ورود اضافه کنید. این دو قالب فرم جایی هستند که از Django Crispy Forms استفاده می شود.

 

Stripe را نصب کنید

خط فرمان ویندوز

(env)C:\Users\Owner\desktop\env>pip install --upgrade stripe

 

Stripe را نصب کنید.

یک حالت اشتراک ایجاد کنید

env > mysite > main > models.py

from django.db import models

# Create your models here.
class Subscription(models.Model):
    name = models.CharField(max_length=100)
    amount = models.DecimalField(decimal_places=2, max_digits=5)
    stripe_product_id = models.CharField(max_length=100)

    def __str__(self):
        return self.name

 

یک Subscriptionمدل ایجاد کنید. این مدال را به admin.py اضافه کنید و یک superuser برای دسترسی به admin ایجاد کنید.

در ایجاد یک SuperUser جنگو و افزودن اشیاء مدل از طریق ادمین جنگو اقدام کنید.

به  stripe_product_id.  توجه کنید ما این شناسه را در عرض یک ثانیه از Stripe دریافت خواهیم کرد.

 

به Stripe متصل شوید

به داشبورد Stipe خود وارد شوید و “View test data” را روشن کنید.

 

روی دکمه “+ Add product” در سمت راست بالای صفحه کلیک کنید و فرم اطلاعات محصول را پر کنید. ما سه محصول تکرارشونده اضافه خواهیم کرد: Basic، Pro، و Enterprise Plans.

 

اشیاء مدل اشتراک جنگو را ایجاد کنید

به ادمین وارد شوید و طرح اشتراک خود را علاوه بر شناسه منحصر به فرد Stipe API که در داشبورد Stripe پیدا می‌شود، با کلیک روی هر محصول اضافه کنید.

اگر به پیکربندی Django و Stripe برای همگام سازی خودکار علاقه دارید، دستورالعمل های dj-stripe را در استفاده از Django و Stripe برای اشتراک های ماهانه بررسی کنید.

 

یک صفحه قیمت ایجاد کنید

env > mysite > main > templates > main > (New File) pricing.html

{% extends 'main/header.html' %}
{% block content %}
{% load static %}

<script class="lazy" src="https://polyfill.io/v3/polyfill.min.js?version=3.52.1&features=fetch"></script>
<script class="lazy" src="https://js.stripe.com/v3/"></script>

<!--Pricing-->
    <div class="container p-lg-5 p-3">
    	<h1 class="cta text-center">Pricing</span></h1>
      <h5 class="text-muted lead my-3 text-center">Don't run away from your finances. Jump right in.</h5>
      <div class="row p-lg-5 p-3">


        {% for s in subscription %}
        <div class="col-lg-4 col-md-12 mb-4">
          <div class="card h-100 shadow-lg text-center mx-auto sub-cards" style="max-width:20rem">
          	 <div class="card-header sub-header">
                <h4>{{s.name}}</h4>
              </div>
            <div class="card-body">    
               <h1>${{s.amount}}<span class="text-muted" style="font-weight: 300">/mo</span></h1>
            
        	<p class="my-3">
             {{s.description|safe|linebreaks}}
          </p>
            
            <div class="d-grid">

              {% if user.is_authenticated %}
            	<button class="btn btn-outline-primary btn-block btn-lg sub-button" onclick="selectPlan('{{s.stripe_api_id}}')">Select</button>
              {% else %}
              <a class="btn btn-outline-primary btn-block btn-lg sub-button" href="/register">Select</a>
              {% endif %}
            </div>
          </div>
          </div>
        </div>
        {% endfor %}


      </div>
    </div>

    <script type="text/javascript">

    //grabs csrftoken
    let cookie = document.cookie
    let cookies = cookie.substring(cookie.indexOf('csrftoken=') + 10)
    let csrfToken = cookies.split(";")[0]

    // Create an instance of the Stripe object with your publishable API key
    var stripe = Stripe("pk_test"); //replace with your Stripe API key

    function selectPlan(pid) {
      fetch("/create-checkout-session", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-CSRFToken": csrfToken, 
        },
        body: JSON.stringify({
          product_id: pid
        })
      })
        .then(function (response) {
          return response.json();
        })
        .then(function (session) {
          return stripe.redirectToCheckout({ sessionId: session.id });
        })
        .then(function (result) {
          // If redirectToCheckout fails due to a browser or network
          // error, you should display the localized error message to your
          // customer using error.message.
          if (result.error) {
            alert(result.error.message);
          }
        })
        .catch(function (error) {
          console.error("Error:", error);
        });
    } 
    </script>
<!--End Pricing-->

{% endblock %}

رمز CSRF را برای ارسال پست بگیرید، سپس کلید Stripe API خود را بارگیری کنید. و بعد selectPlan(). را اضافه کنید  این تابع شناسه منحصر به فرد API Stripe را برای هر محصول دریافت می کند.

/create-checkout-sessionURL اضافه شده در مرحله بعد را واکشی کنید و به product_idعنوان JSON پست کنید.

سپس پاسخ JSON و تغییر مسیر Stripe را به صفحه پرداخت Stripe برگردانید.

 

urls.py را به روز کنید

env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"   


urlpatterns = [
    path("", views.homepage, name="homepage"),
    path("dashboard", views.dashboard, name="dashboard"),
    path("register", views.register_request, name="register"),
    path("login", views.login_request, name="login"),
    path("logout", views.logout_request, name= "logout"),
    path("create-checkout-session", views.create_checkout_session, name="create checkout session"),
    path('success', views.success_request, name="success"),
    path('cancel', views.cancel_request, name="cancel"),
    path('pricing', views.pricing, name="pricing"),

]

urls.py را با همه الگوهای URL لازم به روز کنید. ، create-checkout-sessionو success_requestهمه cancel_requestالگوهای URL برای اشتراک های ماهانه Stripe.

 

views.py را به روز کنید

env > mysite > main > views.py

from django.shortcuts import  render, redirect
from .forms import NewUserForm
from django.contrib.auth import login, authenticate, logout
from django.contrib import messages
from django.contrib.auth.forms import AuthenticationForm
from .models import Subscription
from django.http import HttpResponse, JsonResponse
import stripe
import json


# Create your views here.
def homepage(request):
    return render(request = request, template_name="main/home.html")

def pricing(request):
    subscription = Subscription.objects.all()
    return render(request = request, template_name="main/pricing.html", context={"subscription":subscription})

def dashboard(request):
    return render(request = request, template_name="main/dashboard.html")


def register_request(request):
    if request.method == "POST":
        form = NewUserForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            messages.success(request, "Registration successful." )
            return redirect("main:pricing")
        messages.error(request, "Unsuccessful registration. Invalid information.")
    email = request.GET.get("email")
    data = {"email":email}
    form = NewUserForm(initial=data)
    return render (request=request, template_name="main/register.html", context={"register_form":form})

def login_request(request):
    if request.method == "POST":
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                return redirect("main:dashboard")
            else:
                messages.error(request,"Invalid username or password.")
        else:
            messages.error(request,"Invalid username or password.")
    form = AuthenticationForm()
    return render(request=request, template_name="main/login.html", context={"login_form":form})

def logout_request(request):
    logout(request)
    messages.info(request, "You have successfully logged out.") 
    return redirect("main:homepage")

def create_checkout_session(request):
    if request.method == "POST":
        YOUR_DOMAIN = 'http://127.0.0.1:8000'
        stripe.api_key = 'sk_test' #replace with your Stripe API key
        data = json.loads(request.body)

        customer = stripe.Customer.create(
            email=request.user.email)
        try:
            checkout_session = stripe.checkout.Session.create(
                payment_method_types=['card'],
                line_items=[
                    {
                        'price': data["product_id"],
                        'quantity': 1,
                    }
                ],
                mode='subscription',
                success_url=YOUR_DOMAIN + '/success',
                cancel_url=YOUR_DOMAIN + '/cancel',
                customer_email = customer.email,
                )
            return JsonResponse({'id': checkout_session.id})
        except Exception as e:
            return JsonResponse({'error': (e.args[0])}, status =400)
    return JsonResponse({'error':'No GET request allowed.'})

def success_request(request):
    messages.info(request, "You have successfully subscribed.") 
    return redirect("main:dashboard")

def cancel_request(request):
    messages.info(request, "Payment Failed. Please try again.") 
    return redirect("main:pricing")

بیایید روی سه عملکرد آخر تمرکز کنیم. create_checkout_session()بارگذاری در داده‌های JSON از صفحه قیمت‌گذاری، یک مشتری خطی ایجاد می‌کند، سپس سعی می‌کند جلسه پرداخت Stripe را ایجاد کند.

payment_method_types, the را line_itemsاز داده‌های JSON, the modesuccess_urlcancel_urlو اعلان کنید customer_email. در آخر، شناسه جلسه پرداخت را برگردانید.

در صورت موفقیت آمیز بودن اشتراک، درخواست success_request()کنید و اگر جلسه پرداخت لغو شد، request cancel_request().

 

نتیجه گیری

این آموزش هم به پایان رسید مانند دیگر آموزشی های پایتونی ها و اکنون شما یک الگوی پایه SaaS دارید که می توانید آن را تکرار کرده و MVP جدید خود را ایجاد کنید.

محمدرضا حسنی

224 مطلب منتشر شده

دانش آموخته رشته فناوری اطلاعات / موسس پایتونی ها

درباره این مطلب نظر دهید !

محصولات فروش پایتونی ها

%69
تخفیف

آموزش برنامه نویسی پایتون

35,000 تومان
6
%60
تخفیف

آموزش فیگما (Figma)

30,000 تومان
3