2021年7月30日 星期五

好玩的WebVR,A-Fame一個針對3D/AR/VR所設計的網路框架

A-Frame 無需安裝任何東西,採用 HTML 文件開發,使其易於上手用於構建虛擬實境 (VR) 體驗的網路框架。A-Frame 不僅僅是 3D 場景圖或標記語言,它的核心更是一個強大的實體組件框架

網址:https://aframe.io/

範例一:


程式碼:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
  <head>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

範例二:

程式碼:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>Model Viewer AR - VR</title>
  <meta name="description" content="Model Viewer (VR / AR) • A-Frame">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
  <script src="info-message.js"></script>
  <script src="https://unpkg.com/aframe-extras@3.3.0/dist/aframe-extras.min.js"></script>
  <script src="hide-on-enter-ar.js"></script>
  <script src="ar-shadows.js"></script>
  <script src="ar-hit-test.js"></script>
  <script src="model-viewer.js"></script>
  <script src="background-gradient.js"></script>
</head>
<body>

<a-scene
  renderer="colorManagement: true;"
  info-message="htmlSrc: #messageText"
  model-viewer="gltfModel: #triceratops; title: Triceratops">
  <a-assets>
    <!--
      Model source: https://sketchfab.com/3d-models/triceratops-d16aabe33dc24f8ab37e3df50c068265
      Model author: https://sketchfab.com/VapTor
      Model license: Sketcfab Standard
    -->
    <a-asset-item id="triceratops"
      src="https://cdn.aframe.io/examples/ar/models/triceratops/scene.gltf"
      response-type="arraybuffer" crossorigin="anonymous"></a-asset-item>

    <a-asset-item id="reticle"
      src="https://cdn.aframe.io/examples/ar/models/reticle/reticle.gltf"
      response-type="arraybuffer" crossorigin="anonymous"></a-asset-item>

    <img id="shadow" src="https://cdn.glitch.com/20600112-c04b-492c-8190-8a5ccc06f37d%2Fshadow.png?v=1606338852399"></img>
    <a-asset-item id="messageText" src="message.html"></a-asset-item>
  </a-assets>
</a-scene>
</body>
</html>

2021年6月14日 星期一

Django-oscar重量級電子商店測試初體驗心得分享


看到django-oscar網站上的案例分享如上圖,就能感受到這款電子商店的媚力,再看到下圖在Github的星級也高達5k,一定要動手下載來測試看看。

 但測試過程似乎不怎麼方便,經過幾番的測試,查詢錯誤的訊息,找到相關解決方法,最後整理出下面的的套件,供大家在測試OSCAR沙盒的參考。


最後的測試結果為:




2021年6月12日 星期六

Django 3和Bootstrap 5聯手展現布農族拉芙嵐文化特色




程式碼參考網址:https://getbootstrap.com/docs/5.0/components/carousel/

1.準備三張拉芙嵐的特色照片,利用小畫家修成1920X750,儲存在shop/static/slider目錄下,並分別命名為bg1.jpg, bg2.jpg, 以及bg3.jpg。

2.把參考的程式貼在shop/templates/shop/base.html中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
{% load static %}
{% load bootstrap5 %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <link href="https://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    {% bootstrap_css %}
    {% bootstrap_javascript %}

</head>
<body>

<div class="container">
    <div class="page-header">
        <a href="/"><h1 class="display-7">拉芙嵐雙龍七彩服務平台</h1></a>
    </div>
<div id="carouselExampleIndicators" class="carousel slide  wet-asphalt" data-bs-ride="carousel">
  <div class="carousel-indicators">
    <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
    <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1" aria-label="Slide 2"></button>
    <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2" aria-label="Slide 3"></button>
  </div>
  <div class="carousel-inner">
    <div class="carousel-item active">
      <img src="{% static "slider/bg1.jpg" %}" class="d-block w-100" alt="...">
    </div>
    <div class="carousel-item">
      <img src="{% static "slider/bg2.jpg" %}" class="d-block w-100" alt="...">
    </div>
    <div class="carousel-item">
      <img src="{% static "slider/bg3.jpg" %}" class="d-block w-100" alt="...">
    </div>
  </div>
  <button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="prev">
    <span class="carousel-control-prev-icon" aria-hidden="false"></span>
    <span class="visually-hidden">Previous</span>
  </button>
  <button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="next">
    <span class="carousel-control-next-icon" aria-hidden="false"></span>
    <span class="visually-hidden">Next</span>
  </button>
</div>
    <div class="panel panel-default">
        <div class="panel-heading">
            {# call __len__ #}
            {% with total_items=cart|length %}
                {% if cart|length > 0 %}
                    Your cart:
                    <a href="{% url "cart:cart_detail" %}">
                        {# If total_items is 1, the output will be 1 item. #}
                        {# If total_items is 2, the output will be 2 items. #}
                        {{ total_items }} item{{ total_items|pluralize }},
                        ${{ cart.get_total_price }}
                    </a>
                {% else %}
                    Your shopping cart is empty.
                {% endif %}
            {% endwith %}
        </div>
    </div>

    {% block content %}
    {% endblock %}
</div>
</body>
</html>

使用Bootstrap5為電子購物網站換新裝

 前一篇文章我們把Django升級到3.2.4版,本篇文章我們來把Bootstrap3升級為Bootstrap5,步驟如下:

1,安裝dajngo-bootstrap-v5


2.使用pip list檢查安裝的套件,發現bootstrap3以及bootstrap-v5都在shopenv環境中。


3.使用pip uninstall 命令來移除bootstrap3


5.修改設定檔django_shop_tutorial/settings.py,將bootstrap3改為bootstrap5。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bootstrap5',
    'shop',
    'cart',
    'orders',
    'paypal.standard.ipn',
    'payment',
]

5.修改樣版

(1)shop/templates/shop/base.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{% load static %}
{% load bootstrap5 %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <link href="https://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    {% bootstrap_css %}
    {% bootstrap_javascript %}

</head>
<body>

<div class="container">
    <div class="page-header">
        <a href="/"><h1 class="display-1">My shop</h1></a>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">
            {# call __len__ #}
            {% with total_items=cart|length %}
                {% if cart|length > 0 %}
                    Your cart:
                    <a href="{% url "cart:cart_detail" %}">
                        {# If total_items is 1, the output will be 1 item. #}
                        {# If total_items is 2, the output will be 2 items. #}
                        {{ total_items }} item{{ total_items|pluralize }},
                        ${{ cart.get_total_price }}
                    </a>
                {% else %}
                    Your shopping cart is empty.
                {% endif %}
            {% endwith %}
        </div>
    </div>

    {% block content %}
    {% endblock %}
</div>
</body>
</html>

(2)shop/templates/shop/product/list.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{% extends "shop/base.html" %}
{% load static %}

{% block title %}
    {% if category %}{{ category.name }}{% else %}Products{% endif %}
{% endblock %}

{% block content %}

    <div class="row">
        <div class="col-md-3">
            <h3>Categories</h3>
            <ul class="nav flex-column">
                <li {% if not category %}class="nav-item"{% endif %}>
                    <a href="{% url "shop:product_list" %}">All</a></li>
                {% for c in categories %}
                    <li {% if category.slug == c.slug %}class="nav-item"{% endif %}>
                        <a href="{{ c.get_absolute_url }}">{{ c.name }}</a>
                    </li>
                {% endfor %}
            </ul>
        </div>

        <div class="col-md-9">
            <h2>{% if category %}{{ category.name }}{% else %}Products{% endif %}</h2>
            <div class="row">
                {% for product in products %}
                    <div class="col-md-4">
                        <div class="thumbnail">
                            <a href="{{ product.get_absolute_url }}">
                                <img class="img-thumbnail" src="{% if product.image %}{{ product.image.url }}
                                          {% else %}{% static "img/no_image.png" %} {% endif %}">
                            </a>
                            <a href="{{ product.get_absolute_url }}">{{ product.name }}</a><br>
                            ${{ product.price }}
                        </div>
                    </div>
                {% endfor %}
            </div>


        </div>


    </div>
{% endblock %}

(3)shop/templates/shop/product/detail/html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{% extends "shop/base.html" %}
{% load static %}
{% load bootstrap5 %}

{% block title %}
    {% if category %}{{ category.title }}{% else %}Products{% endif %}
{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-12">
            <div class="col-md-6 col-md-4">

            </div>
            <div class="col-md-6 col-md-4">
                <div class="thumbnail">
                    <img class="img-fluid" src="{% if product.image %}{{ product.image.url }}
                              {% else %}{% static "img/no_image.png" %}{% endif %}"
                         class="img-responsive">
                    <div class="caption">
                        <div class="row">
                            <div class="col-md-6 col-xs-6">
                                <h3>{{ product.name }}</h3>
                            </div>
                            <div class="col-md-6 col-xs-6 price">
                                <h3>
                                    <label>${{ product.price }}</label></h3>
                            </div>
                        </div>
                        <p>{{ product.description }}</p>
                        <h2><a href="{{ product.category.get_absolute_url }}">{{ product.category }}</a></h2>
                        <form action="{% url "cart:cart_add" product.id %}" method="post">
                            {% csrf_token %}
                            {% bootstrap_form cart_product_form %}
                            {% buttons %}
                                <button type="submit" class="btn btn-success btn-product">
                                    <span class="glyphicon glyphicon-shopping-cart"></span> Add to cart
                                </button>
                            {% endbuttons %}
                        </form>

                        <p></p>
                    </div>
                </div>
            </div>
            <div class="col-md-6 col-md-4">

            </div>
        </div>

    </div>


{% endblock %}

(4)cart/templates/cart/detail/html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{% extends "shop/base.html" %}
{% load static %}
{% load bootstrap5 %}
{% block title %}
    Your shopping cart
{% endblock %}

{% block content %}
    <h1>Your shopping cart</h1>

    <div class="row">
        <div class="col-sm-12 col-md-10 col-md-offset-1">
            <table class="table table-hover">
                <thead>
                <tr>
                    <th>Product</th>
                    <th>Quantity</th>
                    <th class="text-center">Price</th>
                    <th class="text-center">Total</th>
                    <th> </th>
                </tr>
                </thead>
                <tbody>
                {% for item in cart %}
                    {% with product=item.product %}
                        <tr>
                            <td class="col-sm-8 col-md-6">
                                <div class="media">
                                    <a class="thumbnail pull-left" href="{{ product.get_absolute_url }}">
                                        <img class="media-object"
                                             src="{% if product.image %}{{ product.image.url }}
                                                  {% else %}{% static "img/no_image.png" %}{% endif %}"
                                             style="width: 72px; height: 72px;">
                                    </a>
                                    <div class="media-body">
                                        <h4 class="media-heading"><a
                                                href="{{ product.get_absolute_url }}">{{ product.name }}</a></h4>
                                        <span>Status: </span><span class="text-success"><strong>In Stock</strong></span>
                                    </div>
                                </div>
                            </td>
                            <td class="col-sm-1 col-md-1" style="text-align: center">
                                <form action="{% url "cart:cart_add" product.id %}" method="post">
                                    {% csrf_token %}
                                    {% bootstrap_field item.update_quantity_form.quantity show_label=False %}
                                    {% bootstrap_field item.update_quantity_form.update %}
                                    {% buttons %}
                                        <button type="submit" class="btn btn-success btn-product">
                                            Update
                                        </button>
                                    {% endbuttons %}
                                </form>
                            </td>

                            <td class="col-sm-1 col-md-1 text-center"><strong>${{ item.price }}</strong></td>
                            <td class="col-sm-1 col-md-1 text-center"><strong>${{ item.total_price }}</strong></td>

                            <td class="col-sm-1 col-md-1">
                                <a href="{% url "cart:cart_remove" product.id %}" class="btn btn-danger">
                                    <i class="glyphicon glyphicon-remove" aria-hidden="true"></i> Remove
                                </a>
                            </td>
                        </tr>
                    {% endwith %}
                {% endfor %}
                <tr>
                    <td>  </td>
                    <td>  </td>
                    <td>  </td>
                    <td><h3>Total</h3></td>
                    <td class="text-right"><h3><strong>${{ cart.get_total_price }}</strong></h3></td>
                </tr>
                <tr>
                    <td>  </td>
                    <td>  </td>
                    <td>  </td>
                    <td>
                        <a href="{% url "shop:product_list" %}" class="btn btn-default">
                            Continue Shopping <i class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></i>
                        </a>
                    </td>
                    <td>
                        <a href="{% url "orders:order_create" %}" class="btn btn-default">Checkout <i
                                class="glyphicon glyphicon-play" aria-hidden="true"></i>
                        </a>
                    </td>
                </tr>
                </tbody>
            </table>
        </div>
    </div>

{% endblock %}


四個步驟輕鬆升級Django最新版電子購物網站

為回應讀者反應Django版本太低,應該要用新版的Django,由於原作者twtrubiks在四年前就發展這個專案-twtrubiks/django-shop-tutorial,因此必須將Django版本改成Djangle 1.11.29,才能順利編譯完成。目前Django已經升級到3.2.4,以下四個步驟升級為Django 3.2.4版。

1.修改urls.py,有兩個重點,其一是include函式的參數,其二是除了django_shop_tutorial目錄下的urls.py不需要加上設定app_name變數值,其餘的urls.py都要也就是經由include函式的urls都需要。

(1) django_shop_tutorial/urls.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
"""django_shop_tutorial URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf import settings
from django.conf.urls import url, include
from django.conf.urls.static import static
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^cart/', include('cart.urls')),
    url(r'^orders/', include('orders.urls')),
    url(r'^payment/', include('payment.urls')),
    url(r'^paypal/', include('paypal.standard.ipn.urls')),
    url(r'^', include('shop.urls')),

]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)

(2)shop/urls.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from django.conf.urls import url

from . import views
app_name = 'shop'


urlpatterns = [
    url(r'^$', views.product_list,
        name='product_list'),
    url(r'^(?P<category_slug>[-\w]+)/$',
        views.product_list,
        name='product_list_by_category'),
    url(r'^(?P<product_id>\d+)/(?P<slug>[-\w]+)/$',
        views.product_detail,
        name='product_detail')
    ]

(3)payment/urls.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from django.conf.urls import url
from . import views
app_name = 'payment'

urlpatterns = [
    url(r'^process/$', views.payment_process
        , name='process'),
    url(r'^done/$', views.payment_done
        , name='done'),
    url(r'^canceled/$', views.payment_canceled
        , name='canceled'),
]

(4)order/urls.py
1
2
3
4
5
6
7
8
9
from django.conf.urls import url
from . import views
app_name = 'orders'

urlpatterns = [
        url(r'^create/$',
            views.order_create,
            name='order_create'),
]

(5)cart/urls.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.conf.urls import url

from . import views
app_name = 'cart'

urlpatterns = [
    url(r'^$', views.cart_detail,
        name='cart_detail'),
    url(r'^add/(?P<product_id>\d+)/$',
        views.cart_add,
        name='cart_add'),
    url(r'^remove/(?P<product_id>\d+)/$',
        views.cart_remove,
        name='cart_remove'),
]

2.修改models,有兩個重點,其一是django.core.urlresolvers套件由django.urls套件取代,其二是ForeignKey參數必須要指定on_delete參數值。
(1)shop/models.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from django.urls import reverse
from django.db import models


class Category(models.Model):
    name = models.CharField(max_length=200,
                            db_index=True)
    slug = models.SlugField(max_length=200,
                            db_index=True,
                            unique=True)

    class Meta:
        ordering = ('name',)
        verbose_name = 'category'
        verbose_name_plural = 'categories'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('shop:product_list_by_category',
                       args=[self.slug])


class Product(models.Model):
    category = models.ForeignKey(Category,
                                 related_name='products', on_delete=models.CASCADE)
    name = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField(max_length=200, db_index=True)
    image = models.ImageField(upload_to='products/%Y/%m/%d',
                              blank=True)
    description = models.TextField(blank=True)
    # 台灣價錢都是整數,所以可以設定 decimal_places=0
    price = models.DecimalField(max_digits=10, decimal_places=0)
    stock = models.PositiveIntegerField()
    available = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ('name',)
        index_together = (('id', 'slug'),)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('shop:product_detail',
                       args=[self.id, self.slug])

(2) order/models.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from django.db import models

from shop.models import Product


class Order(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    email = models.EmailField()
    address = models.CharField(max_length=250)
    postal_code = models.CharField(max_length=20)
    city = models.CharField(max_length=100)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    paid = models.BooleanField(default=False)

    class Meta:
        ordering = ('-created',)

    def __str__(self):
        return 'Order {}'.format(self.id)

    def get_total_cost(self):
        return sum(item.get_cost() for item in self.items.all())


class OrderItem(models.Model):
    order = models.ForeignKey(Order,
                              related_name='items', on_delete=models.CASCADE)
    product = models.ForeignKey(Product,
                                related_name='order_items', on_delete=models.CASCADE)
    # 台灣價錢都是整數,所以可以設定 decimal_places=0
    price = models.DecimalField(max_digits=10, decimal_places=0)
    quantity = models.PositiveIntegerField(default=1)

    def __str__(self):
        return '{}'.format(self.id)

    def get_cost(self):
        return self.price * self.quantity

3.修改payment/views.py,只需要將django.core.urlresolvers套件由django.urls套件取代。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from decimal import Decimal

from django.conf import settings
from django.urls import reverse
from django.shortcuts import render, get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from paypal.standard.forms import PayPalPaymentsForm

from orders.models import Order


def payment_process(request):
    order_id = request.session.get('order_id')
    order = get_object_or_404(Order, id=order_id)
    host = request.get_host()
    paypal_dict = {
        'business': settings.PAYPAL_RECEIVER_EMAIL,
        'amount': '%.2f' % order.get_total_cost().quantize(
            Decimal('.01')),
        'item_name': 'Order {}'.format(order.id),
        'invoice': str(order.id),
        'currency_code': 'TWD',
        'notify_url': 'http://{}{}'.format(host,
                                           reverse('paypal-ipn')),
        'return_url': 'http://{}{}'.format(host,
                                           reverse('payment:done')),
        'cancel_return': 'http://{}{}'.format(host,
                                              reverse('payment:canceled')),
    }
    form = PayPalPaymentsForm(initial=paypal_dict)
    return render(request,
                  'payment/process.html',
                  {'order': order, 'form': form})


@csrf_exempt
def payment_done(request):
    return render(request, 'payment/done.html')


@csrf_exempt
def payment_canceled(request):
    return render(request, 'payment/canceled.html')

4.修改templates,只需要修staticfiles成為static即可。
(1)shop/templates/shop/base.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{% load static %}
{% load bootstrap3 %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <link href="https://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    {% bootstrap_css %}
    {% bootstrap_javascript %}

</head>
<body>

<div class="container">
    <div class="page-header">
        <a href="/"><h1>My shop</h1></a>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">
            {# call __len__ #}
            {% with total_items=cart|length %}
                {% if cart|length > 0 %}
                    Your cart:
                    <a href="{% url "cart:cart_detail" %}">
                        {# If total_items is 1, the output will be 1 item. #}
                        {# If total_items is 2, the output will be 2 items. #}
                        {{ total_items }} item{{ total_items|pluralize }},
                        ${{ cart.get_total_price }}
                    </a>
                {% else %}
                    Your shopping cart is empty.
                {% endif %}
            {% endwith %}
        </div>
    </div>

    {% block content %}
    {% endblock %}
</div>
</body>
</html>

(2)shop/templates/shop/product/detail.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{% extends "shop/base.html" %}
{% load static %}
{% load bootstrap3 %}

{% block title %}
    {% if category %}{{ category.title }}{% else %}Products{% endif %}
{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-12">
            <div class="col-md-6 col-md-4">

            </div>
            <div class="col-md-6 col-md-4">
                <div class="thumbnail">
                    <img src="{% if product.image %}{{ product.image.url }}
                              {% else %}{% static "img/no_image.png" %}{% endif %}"
                         class="img-responsive">
                    <div class="caption">
                        <div class="row">
                            <div class="col-md-6 col-xs-6">
                                <h3>{{ product.name }}</h3>
                            </div>
                            <div class="col-md-6 col-xs-6 price">
                                <h3>
                                    <label>${{ product.price }}</label></h3>
                            </div>
                        </div>
                        <p>{{ product.description }}</p>
                        <h2><a href="{{ product.category.get_absolute_url }}">{{ product.category }}</a></h2>
                        <form action="{% url "cart:cart_add" product.id %}" method="post">
                            {% csrf_token %}
                            {% bootstrap_form cart_product_form %}
                            {% buttons %}
                                <button type="submit" class="btn btn-success btn-product">
                                    <span class="glyphicon glyphicon-shopping-cart"></span> Add to cart
                                </button>
                            {% endbuttons %}
                        </form>

                        <p></p>
                    </div>
                </div>
            </div>
            <div class="col-md-6 col-md-4">

            </div>
        </div>

    </div>


{% endblock %}

(3)shop/templates/shop/product/list.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{% extends "shop/base.html" %}
{% load static %}

{% block title %}
    {% if category %}{{ category.name }}{% else %}Products{% endif %}
{% endblock %}

{% block content %}

    <div class="row">
        <div class="col-md-3">
            <h3>Categories</h3>
            <ul class="nav nav-pills nav-stacked">
                <li {% if not category %}class="active"{% endif %}>
                    <a href="{% url "shop:product_list" %}">All</a></li>
                {% for c in categories %}
                    <li {% if category.slug == c.slug %}class="active"{% endif %}>
                        <a href="{{ c.get_absolute_url }}">{{ c.name }}</a>
                    </li>
                {% endfor %}
            </ul>
        </div>

        <div class="col-md-9">
            <h2>{% if category %}{{ category.name }}{% else %}Products{% endif %}</h2>
            <div class="row">
                {% for product in products %}
                    <div class="col-md-4">
                        <div class="thumbnail">
                            <a href="{{ product.get_absolute_url }}">
                                <img src="{% if product.image %}{{ product.image.url }}
                                          {% else %}{% static "img/no_image.png" %} {% endif %}">
                            </a>
                            <a href="{{ product.get_absolute_url }}">{{ product.name }}</a><br>
                            ${{ product.price }}
                        </div>
                    </div>
                {% endfor %}
            </div>


        </div>


    </div>
{% endblock %}

(4)cart/templates/detail.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{% extends "shop/base.html" %}
{% load static %}
{% load bootstrap3 %}
{% block title %}
    Your shopping cart
{% endblock %}

{% block content %}
    <h1>Your shopping cart</h1>

    <div class="row">
        <div class="col-sm-12 col-md-10 col-md-offset-1">
            <table class="table table-hover">
                <thead>
                <tr>
                    <th>Product</th>
                    <th>Quantity</th>
                    <th class="text-center">Price</th>
                    <th class="text-center">Total</th>
                    <th> </th>
                </tr>
                </thead>
                <tbody>
                {% for item in cart %}
                    {% with product=item.product %}
                        <tr>
                            <td class="col-sm-8 col-md-6">
                                <div class="media">
                                    <a class="thumbnail pull-left" href="{{ product.get_absolute_url }}">
                                        <img class="media-object"
                                             src="{% if product.image %}{{ product.image.url }}
                                                  {% else %}{% static "img/no_image.png" %}{% endif %}"
                                             style="width: 72px; height: 72px;">
                                    </a>
                                    <div class="media-body">
                                        <h4 class="media-heading"><a
                                                href="{{ product.get_absolute_url }}">{{ product.name }}</a></h4>
                                        <span>Status: </span><span class="text-success"><strong>In Stock</strong></span>
                                    </div>
                                </div>
                            </td>
                            <td class="col-sm-1 col-md-1" style="text-align: center">
                                <form action="{% url "cart:cart_add" product.id %}" method="post">
                                    {% csrf_token %}
                                    {% bootstrap_field item.update_quantity_form.quantity show_label=False %}
                                    {% bootstrap_field item.update_quantity_form.update %}
                                    {% buttons %}
                                        <button type="submit" class="btn btn-success btn-product">
                                            Update
                                        </button>
                                    {% endbuttons %}
                                </form>
                            </td>

                            <td class="col-sm-1 col-md-1 text-center"><strong>${{ item.price }}</strong></td>
                            <td class="col-sm-1 col-md-1 text-center"><strong>${{ item.total_price }}</strong></td>

                            <td class="col-sm-1 col-md-1">
                                <a href="{% url "cart:cart_remove" product.id %}" class="btn btn-danger">
                                    <i class="glyphicon glyphicon-remove" aria-hidden="true"></i> Remove
                                </a>
                            </td>
                        </tr>
                    {% endwith %}
                {% endfor %}
                <tr>
                    <td>  </td>
                    <td>  </td>
                    <td>  </td>
                    <td><h3>Total</h3></td>
                    <td class="text-right"><h3><strong>${{ cart.get_total_price }}</strong></h3></td>
                </tr>
                <tr>
                    <td>  </td>
                    <td>  </td>
                    <td>  </td>
                    <td>
                        <a href="{% url "shop:product_list" %}" class="btn btn-default">
                            Continue Shopping <i class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></i>
                        </a>
                    </td>
                    <td>
                        <a href="{% url "orders:order_create" %}" class="btn btn-default">Checkout <i
                                class="glyphicon glyphicon-play" aria-hidden="true"></i>
                        </a>
                    </td>
                </tr>
                </tbody>
            </table>
        </div>
    </div>

{% endblock %}