2019年11月30日 星期六

Mezzanine 樣板上傳 heroku 網站-2019南投市Python/Django part5

前置動作:
1. install Git
https://git-scm.com/
2. install Heroku Cli
https://devcenter.heroku.com/categories/command-line
3. 申請 Heroku 帳號
Heroku | 搭配 Git 在 Heroku 上部署網站的手把手教學
5.準備好上傳網頁
5.1下載免費主題
https://github.com/thecodinghouse/mezzanine-themes
5.2下載並解壓縮整理好備用




1. 安裝虛擬工作環境
mkvirtualenv your-project-name

2. 安裝 Mezzanine
pip install mezzanine

3. 安裝購物車套件(選配, 有需要者裝)
pip install –U cartridge


4. 建立 Mezzanine 專案
mezzanine-project your-project-name

5. 切換至內容網站的工作目錄 , 並新增檔案 Procfile
5.1  cd your-project-name
5.2 建立新檔案 Procfile
內容如下(注意 your-project-name 是替換成自己的專案名稱。)
web: gunicorn --pythonpath your-project-name your-project-name.wsgi

完成時存檔時, 請注意
Procfile - Procfile - P要大寫,
                不要有副檔名

6. 編輯 wsgi.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
"""
WSGI config for mymezzanine project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application
from mezzanine.utils.conf import real_project_name
from dj_static import Cling

os.environ.setdefault("DJANGO_SETTINGS_MODULE",
                      "%s.settings" % real_project_name("mymezzanine"))

application = Cling(get_wsgi_application())



7. 修訂 settings.py,
7.1 時區 TIME_ZONE = 'Asia/Taipei'
7.2 LANGUAGE_CODE = "zh-tw
7.3多語言新增  ('zh-tw', _('繁體中文')), )
7.4 USE_I18N = True
7.5 最下方加入三行
SECRET_KEY = "由 local_settings.py 複製而來"
ALLOWED_HOSTS = ["*"]
STATIC_ROOT = 'static'



# system time zone.
TIME_ZONE = 'Asia/Taipei' (約104列)

# If you set this to True, Django will use timezone-aware datetimes.
USE_TZ = True

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = "zh-tw"   (約111列)

# Supported languages
LANGUAGES = (
    ('en', _('English')),
    ('zh-tw', _('繁體中文')), (約116列)
)

# A boolean that turns on/off debug mode. When set to ``True``, stack traces
# are displayed for error pages. Should always be set to ``False`` in
# production. Best set to ``True`` in local_settings.py
DEBUG = False

# Whether a user's session cookie expires when the Web browser is closed.
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True    (約 131列, 將False 改為 True)
.
.
try:
    from mezzanine.utils.conf import set_dynamic_settings
except ImportError:
    pass
else:
    set_dynamic_settings(globals())   #最下方加入
SECRET_KEY = "o^2ywlr-(!28f8+635em#kxugxw*"  (本列由local_settings.py複製)
 
ALLOWED_HOSTS = ["*"] 
 
STATIC_ROOT = 'static' 
 


8. 套用免費樣板(template)
8.1 選擇使用 moderna 樣版目錄複製到 your-project-name 目錄內(與manage.py同目錄內)
8.2 settings.py設定moderna
 8.2.1 設定template的工作目錄
 8.2.2 INSTALLED_APP 加入 moderna

.
.
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            os.path.join(PROJECT_ROOT, "moderna/templates")
            #os.path.join(PROJECT_ROOT,"templates")
        ],
.
.
INSTALLED_APPS = (
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.redirects",
    "django.contrib.sessions",
    "django.contrib.sites",
    "django.contrib.sitemaps",
    "django.contrib.staticfiles",
    "moderna",
    "mezzanine.boot",
    "mezzanine.conf",
.
.



9. 新增 production_settings.py, 設定 Heroku 佈署命令,儲存在
your-project-name/your-project-name/production_settings.py

# Import all default settings. 
from .settings import *

import dj_database_url
DATABASES = {
    'default': dj_database_url.config(),
}

# Static asset configuration. 
STATIC_ROOT = 'static'

# Honor the 'X-Forwarded-Proto' header for request.is_secure().
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers. 
ALLOWED_HOSTS = ['*']

# Turn off DEBUG mode.
DEBUG = False




10. 執行收集靜態檔案
python manage.py collectstatic

11. 編輯 .gitignore
要把 static 目錄下的檔案上傳,必須要.gitignore 檔案內的/static 刪除

*.pyc
*.pyo
*.db
.DS_Store
.coverage
local_settings.py
/static  刪除此行


12. 安裝 django_heroku 套件
pip install django_heroku

13. 安裝 gunicorn 套件
pip install gunicorn

14. 安裝 dj_staic 套件
pip install dj_static

15. 安裝
pip install psycopg2-binary

16. 設定初始化資料庫
python manage.py createdb

Creating default account....
username:admin
Email: xxx@gmail.com
passward: 1234

17. 製作需求套件的檔案
pip freeze >requirements.txt

18. 工作目錄下執行, , 本地端檢視網站是否可正常執行
python manage.py runserver

19. 執行 git 安裝git之前就開了cmd視窗,請重新開啟它。)
git init
git add .
git commit –m “initial commit”

第一次使用時
git config --global user.email "xxx@gmail.com"
git config --global user.name "xxx"


20. 登入 Heroku (command 視窗輸入, 會在瀏覽器開啟登入頁面)
heroku login
按下 enter 鍵

點擊 login 後,回到 cmd 等待

21. 建立網站
heroku create your-project-name

22 到 heroku your-project-name設定  buildpack 到 Python

23. 設定初始化
heroku config:set DISABLE_COLLECTSTATIC=1

24. 上傳到網站
git push heroku master

25. 設定 (your-project-name修改為自己的專案名稱)
heroku config:set DJANGO_SETTINGS_MODULE=your-project-name.production_settings

26. 第一次佈署
heroku ps:scale web=1

27. 初始化資料庫
heroku run python manage.py createdb

28. 建立使用者帳號
heroku run python manage.py createsuperuser
admin 1234

29. 開啟網站 (自動開啟瀏覽器)
heroku open

30. 開啟失敗, 檢視 log 檔除錯
heroku logs

31重新上傳
git add.
git commit -m "update"  (""內文字可自由更換)
git push heroku master
heroku open

#mezzanine 免費主題flat試做其它page的view

flat這個免費主題首頁的view做成了之後,想來做其它page的view。
因為首頁有明顯的index.html,其它page的html檔案是怎麼一回事呢。

底下以thank身價不凡兩個page為例

  • 首先,觀察網址,不論是中文或是英文的page名稱,都會掛在網址後面。這個和django一樣,就是url的pattern
所以,在url.py中,加入pattern如下
    url(r"^thank/$", views.page, {"slug": "/thank"}, name="thank"),
    url(r"^身價不凡/$",views.page,{"slug":"/身價不凡"},name="身價不凡"),
  • 接著要編輯html檔
  1. 你可以新建一個同名的html,mezzanine會優先使用,但是就無法在admin中管理。
  2. 如果沒有同名的html,mezzanine一律使用pages\page.html來產生各page的html檔(使用者不會看到),你可以在admin中編輯,還可以在page.html中,加入新的元素,例如,接受自己的view傳來的變數。如下藍字是新插入的,由view傳來的變數。page.html中不可以加入文字,那樣會讓每一個page都出現,除非你就是想那樣。
{% block main %}
{{today}}{{arrivaltime}}
{% endblock %}

例一:建身價不凡.html(和page.html放在同一目錄)
<!doctype.html>
<html>
<head>
<title>
</title>
</head>
<body>
<img src="..\..\static\images\car.jpg" >
</body>
</html>
結果,已經不是原來的網頁了。當然你就可以自由的編輯,至於如何引入view,請往下看。
以下和例二相同,只是為了測試中文的url pattern是否可行。
  • 先把身價不凡.html移走,使用mezzanine的page。
  • 在url.py中加入路徑
url(r"^身價不凡/$",views.page,{"slug":"身價不凡"},name="身價不凡"),
  • 在page_processors.py中加入裝飾器
def welcome(request,page):
    hitime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+"  身價不凡"
   
    return locals()

  • 在page.html中加入裝飾器中的變數(藍字部份)(p.s.{{arrivaltime}}是例二中所使用,如果沒作用,就不會顯示)
{% block main %}
{{arrivaltime}}{{hitime}}
{% endblock %}

結果:原來的網頁開頭,加進了時間變數

例二:使用mezzanine內建的page,如上面說明中,在page.html插入藍字部份
{% block main %}
{{arrivaltime}}
{% endblock %}

page_processors.py中加入以下的view程式
from mezzanine.pages.page_processors import processor_for
import time
@processor_for("thank")
def welcome(request,page):
    arrivaltime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    return locals()

結果,星號的上方多了日期和時間。


2019年11月29日 星期五

#修改mezzanine 免費主題flat-->加入自己的view



目標:在網頁中,加入筊白筍每日交易行情

(以下參考的檔案,請到  這個網頁的下方 下載)

準備:
  • 使用django環境,用爬蟲程式,處理好抓回來的資料,在本地端server跑起來。備用。如下圖
(showprice.html和views.py在最下面可下載參考)
  • 已經用mezzanine 主題建立好一個網頁。
mezzanine flat主題的部份
  • 在url.py中,
最上面加入這一行            (mezzanine.pages.views.page()就是專門管view程式的)
from mezzanine.pages import views

把下面這一行註解掉       (這是由mezzanine直接控制的首頁)
 ###url("^$", direct_to_template, {"template": "index.html"}, name="home"),

把下面這一行取消註解    (要用views.page轉向我們的首頁-->flat\templates\pages\index.html,slug是views.page的參數,告訴它要處理的路徑)
url("^$", views.page, {"slug": "/"}, name="home"),

  • 在flat目錄下新建一個檔案,檔名一定叫做page_processors.py,檔案內容和說明參考下面下載檔案。
你發現,我們把爬蟲程式就放在裡面了,只是多了一些設定,還有它只能傳回變數(字典型態),render還是由mezzanine來做。
@processor_for("/")這一行,參數"/"就是類似像「127.0.0.1/」的路徑。
p.s.因為其他頁面是mezzanine的page,所以如果要寫程式套用到這些page,就在url.py中增加路徑,slug後面就加頁面名稱,這裡的參數,也跟著對應就可以了。

  • 進入127.0.0.1:8000/admin,新增一個page,title叫home,在它的最底下有meta標籤,點進去,在url欄位裡填入/
  • 把先前完成的靜態首頁flat\templates\index.html,複製覆蓋flat\templates\pages\index.html,然後編輯它:在你想要的地方,將showprice.html裡面<div>標籤的內容貼上去。

先在本機server跑看看,沒問題,就可以送上heroku了。

[ Django ] 百香果交易行情網站設計(四) - 讓Mezzanine承接自己的意圖


Mezzanine是以Python/Django為基礎發展出來一套很不錯的內容管理系統(Content Management System)套件,只需要約五行指令就能建構很好看的類似於部落格的網站。本篇將說明如何在Mezzanine中加上百香果交易行情資訊。

若是您還不熟悉Mezzanine以及如何取得果菜市場的資訊,請先參考百香果交易行情網站設計前三篇文章,如下:

1.打開urls.py程式 ,瞭解視圖(views)程式是來自mezzanine.core.views中的direct_to_template函式。

  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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
from __future__ import unicode_literals

from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin
from django.views.i18n import set_language

from mezzanine.core.views import direct_to_template
from mezzanine.conf import settings

# Uncomment to use blog as home page. See also urlpatterns section below.
# from mezzanine.blog import views as blog_views

admin.autodiscover()

# Add the urlpatterns for any custom Django applications here.
# You can also change the ``home`` view to add your own functionality
# to the project's homepage.

urlpatterns = i18n_patterns(
    # Change the admin prefix here to use an alternate URL for the
    # admin interface, which would be marginally more secure.
    url("^admin/", include(admin.site.urls)),
)

if settings.USE_MODELTRANSLATION:
    urlpatterns += [
        url('^i18n/$', set_language, name='set_language'),
    ]

urlpatterns += [
    # We don't want to presume how your homepage works, so here are a
    # few patterns you can use to set it up.

    # HOMEPAGE AS STATIC TEMPLATE
    # ---------------------------
    # This pattern simply loads the index.html template. It isn't
    # commented out like the others, so it's the default. You only need
    # one homepage pattern, so if you use a different one, comment this
    # one out.

    url("^$", direct_to_template, {"template": "index.html"}, name="home"),

    # HOMEPAGE AS AN EDITABLE PAGE IN THE PAGE TREE
    # ---------------------------------------------
    # This pattern gives us a normal ``Page`` object, so that your
    # homepage can be managed via the page tree in the admin. If you
    # use this pattern, you'll need to create a page in the page tree,
    # and specify its URL (in the Meta Data section) as "/", which
    # is the value used below in the ``{"slug": "/"}`` part.
    # Also note that the normal rule of adding a custom
    # template per page with the template name using the page's slug
    # doesn't apply here, since we can't have a template called
    # "/.html" - so for this case, the template "pages/index.html"
    # should be used if you want to customize the homepage's template.
    # NOTE: Don't forget to import the view function too!

    # url("^$", mezzanine.pages.views.page, {"slug": "/"}, name="home"),

    # HOMEPAGE FOR A BLOG-ONLY SITE
    # -----------------------------
    # This pattern points the homepage to the blog post listing page,
    # and is useful for sites that are primarily blogs. If you use this
    # pattern, you'll also need to set BLOG_SLUG = "" in your
    # ``settings.py`` module, and delete the blog page object from the
    # page tree in the admin if it was installed.
    # NOTE: Don't forget to import the view function too!

    # url("^$", blog_views.blog_post_list, name="home"),

    # MEZZANINE'S URLS
    # ----------------
    # ADD YOUR OWN URLPATTERNS *ABOVE* THE LINE BELOW.
    # ``mezzanine.urls`` INCLUDES A *CATCH ALL* PATTERN
    # FOR PAGES, SO URLPATTERNS ADDED BELOW ``mezzanine.urls``
    # WILL NEVER BE MATCHED!

    # If you'd like more granular control over the patterns in
    # ``mezzanine.urls``, go right ahead and take the parts you want
    # from it, and use them directly below instead of using
    # ``mezzanine.urls``.
    url("^", include("mezzanine.urls")),

    # MOUNTING MEZZANINE UNDER A PREFIX
    # ---------------------------------
    # You can also mount all of Mezzanine's urlpatterns under a
    # URL prefix if desired. When doing this, you need to define the
    # ``SITE_PREFIX`` setting, which will contain the prefix. Eg:
    # SITE_PREFIX = "my/site/prefix"
    # For convenience, and to avoid repeating the prefix, use the
    # commented out pattern below (commenting out the one above of course)
    # which will make use of the ``SITE_PREFIX`` setting. Make sure to
    # add the import ``from django.conf import settings`` to the top
    # of this file as well.
    # Note that for any of the various homepage patterns above, you'll
    # need to use the ``SITE_PREFIX`` setting as well.

    # ("^%s/" % settings.SITE_PREFIX, include("mezzanine.urls"))

]

# Adds ``STATIC_URL`` to the context of error pages, so that error
# pages can use JS, CSS and images.
handler404 = "mezzanine.core.views.page_not_found"
handler500 = "mezzanine.core.views.server_error"

2.找出mezzanine.core.views中的direct_to_template函式的位置,由於在第二篇文章中,我們建置npf虛擬環境,因此我們可以在Envs\npf\Lib\site-packages\mezzanine\core目錄下,發現views.py。

3.打開mezzanine.core.views.pypy在第67-77行,就可以看到direct_to_template函式。

  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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
from __future__ import absolute_import, unicode_literals
from future.builtins import int, open, str

import os
import mimetypes

from json import dumps

from django.template.response import TemplateResponse

try:
    from urllib.parse import urljoin, urlparse
except ImportError:
    from urlparse import urljoin, urlparse

from django.apps import apps
from django.contrib import admin
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.admin.options import ModelAdmin
from django.contrib.staticfiles import finders
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.http import (HttpResponse, HttpResponseServerError,
                         HttpResponseNotFound)
from django.shortcuts import redirect
from django.template.loader import get_template
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import requires_csrf_token

from mezzanine.conf import settings
from mezzanine.core.forms import get_edit_form
from mezzanine.core.models import Displayable, SitePermission
from mezzanine.utils.views import is_editable, paginate
from mezzanine.utils.sites import has_site_permission
from mezzanine.utils.urls import next_url


mimetypes.init()


@staff_member_required
def set_site(request):
    """
    Put the selected site ID into the session - posted to from
    the "Select site" drop-down in the header of the admin. The
    site ID is then used in favour of the current request's
    domain in ``mezzanine.core.managers.CurrentSiteManager``.
    """
    site_id = int(request.GET["site_id"])
    if not request.user.is_superuser:
        try:
            SitePermission.objects.get(user=request.user, sites=site_id)
        except SitePermission.DoesNotExist:
            raise PermissionDenied
    request.session["site_id"] = site_id
    admin_url = reverse("admin:index")
    next = next_url(request) or admin_url
    # Don't redirect to a change view for an object that won't exist
    # on the selected site - go to its list view instead.
    if next.startswith(admin_url):
        parts = next.split("/")
        if len(parts) > 4 and parts[4].isdigit():
            next = "/".join(parts[:4])
    return redirect(next)


def direct_to_template(request, template, extra_context=None, **kwargs):
    """
    Replacement for Django's ``direct_to_template`` that uses
    ``TemplateResponse`` via ``mezzanine.utils.views.render``.
    """
    context = extra_context or {}
    context["params"] = kwargs
    for (key, value) in context.items():
        if callable(value):
            context[key] = value()
    return TemplateResponse(request, template, context)


@staff_member_required
def edit(request):
    """
    Process the inline editing form.
    """
    model = apps.get_model(request.POST["app"], request.POST["model"])
    obj = model.objects.get(id=request.POST["id"])
    form = get_edit_form(obj, request.POST["fields"], data=request.POST,
                         files=request.FILES)
    if not (is_editable(obj, request) and has_site_permission(request.user)):
        response = _("Permission denied")
    elif form.is_valid():
        form.save()
        model_admin = ModelAdmin(model, admin.site)
        message = model_admin.construct_change_message(request, form, None)
        model_admin.log_change(request, obj, message)
        response = ""
    else:
        response = list(form.errors.values())[0][0]
    return HttpResponse(response)


def search(request, template="search_results.html", extra_context=None):
    """
    Display search results. Takes an optional "contenttype" GET parameter
    in the form "app-name.ModelName" to limit search results to a single model.
    """
    query = request.GET.get("q", "")
    page = request.GET.get("page", 1)
    per_page = settings.SEARCH_PER_PAGE
    max_paging_links = settings.MAX_PAGING_LINKS
    try:
        parts = request.GET.get("type", "").split(".", 1)
        search_model = apps.get_model(*parts)
        search_model.objects.search  # Attribute check
    except (ValueError, TypeError, LookupError, AttributeError):
        search_model = Displayable
        search_type = _("Everything")
    else:
        search_type = search_model._meta.verbose_name_plural.capitalize()
    results = search_model.objects.search(query, for_user=request.user)
    paginated = paginate(results, page, per_page, max_paging_links)
    context = {"query": query, "results": paginated,
               "search_type": search_type}
    context.update(extra_context or {})
    return TemplateResponse(request, template, context)


@staff_member_required
def static_proxy(request):
    """
    Serves TinyMCE plugins inside the inline popups and the uploadify
    SWF, as these are normally static files, and will break with
    cross-domain JavaScript errors if ``STATIC_URL`` is an external
    host. URL for the file is passed in via querystring in the inline
    popup plugin template, and we then attempt to pull out the relative
    path to the file, so that we can serve it locally via Django.
    """
    normalize = lambda u: ("//" + u.split("://")[-1]) if "://" in u else u
    url = normalize(request.GET["u"])
    host = "//" + request.get_host()
    static_url = normalize(settings.STATIC_URL)
    for prefix in (host, static_url, "/"):
        if url.startswith(prefix):
            url = url.replace(prefix, "", 1)
    response = ""
    (content_type, encoding) = mimetypes.guess_type(url)
    if content_type is None:
        content_type = "application/octet-stream"
    path = finders.find(url)
    if path:
        if isinstance(path, (list, tuple)):
            path = path[0]
        if url.endswith(".htm"):
            # Inject <base href="{{ STATIC_URL }}"> into TinyMCE
            # plugins, since the path static files in these won't be
            # on the same domain.
            static_url = settings.STATIC_URL + os.path.split(url)[0] + "/"
            if not urlparse(static_url).scheme:
                static_url = urljoin(host, static_url)
            base_tag = "<base href='%s'>" % static_url
            with open(path, "r") as f:
                response = f.read().replace("<head>", "<head>" + base_tag)
        else:
            try:
                with open(path, "rb") as f:
                    response = f.read()
            except IOError:
                return HttpResponseNotFound()
    return HttpResponse(response, content_type=content_type)


def displayable_links_js(request):
    """
    Renders a list of url/title pairs for all ``Displayable`` subclass
    instances into JSON that's used to populate a list of links in
    TinyMCE.
    """
    links = []
    if "mezzanine.pages" in settings.INSTALLED_APPS:
        from mezzanine.pages.models import Page
        is_page = lambda obj: isinstance(obj, Page)
    else:
        is_page = lambda obj: False
    # For each item's title, we use its model's verbose_name, but in the
    # case of Page subclasses, we just use "Page", and then sort the items
    # by whether they're a Page subclass or not, then by their URL.
    for url, obj in Displayable.objects.url_map(for_user=request.user).items():
        title = getattr(obj, "titles", obj.title)
        real = hasattr(obj, "id")
        page = is_page(obj)
        if real:
            verbose_name = _("Page") if page else obj._meta.verbose_name
            title = "%s: %s" % (verbose_name, title)
        links.append((not page and real, {"title": str(title), "value": url}))
    sorted_links = sorted(links, key=lambda link: (link[0], link[1]['value']))
    return HttpResponse(dumps([link[1] for link in sorted_links]))


@requires_csrf_token
def page_not_found(request, *args, **kwargs):
    """
    Mimics Django's 404 handler but with a different template path.
    """
    context = {
        "STATIC_URL": settings.STATIC_URL,
        "request_path": request.path,
    }
    t = get_template(kwargs.get("template_name", "errors/404.html"))
    return HttpResponseNotFound(t.render(context, request))


@requires_csrf_token
def server_error(request, template_name="errors/500.html"):
    """
    Mimics Django's error handler but adds ``STATIC_URL`` to the
    context.
    """
    context = {"STATIC_URL": settings.STATIC_URL}
    t = get_template(template_name)
    return HttpResponseServerError(t.render(context, request))

4.找出npf/moderna/views.py,只有一行指令。

1
2
3
from django.shortcuts import render

# Create your views here.

5.把步驟3的程式第67-77行,複製到步驟4的程式


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from django.shortcuts import render
from django.template.response import TemplateResponse

# Create your views here.

def direct_to_template(request, template, extra_context=None, **kwargs):
    """
    Replacement for Django's ``direct_to_template`` that uses
    ``TemplateResponse`` via ``mezzanine.utils.views.render``.
    """
    context = extra_context or {}
    context["params"] = kwargs
    for (key, value) in context.items():
        if callable(value):
            context[key] = value()
    return TemplateResponse(request, template, context)

6.修改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
 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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
from __future__ import unicode_literals

from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin
from django.views.i18n import set_language

from moderna.views import direct_to_template
from mezzanine.conf import settings

# Uncomment to use blog as home page. See also urlpatterns section below.
# from mezzanine.blog import views as blog_views

admin.autodiscover()

# Add the urlpatterns for any custom Django applications here.
# You can also change the ``home`` view to add your own functionality
# to the project's homepage.

urlpatterns = i18n_patterns(
    # Change the admin prefix here to use an alternate URL for the
    # admin interface, which would be marginally more secure.
    url("^admin/", include(admin.site.urls)),
)

if settings.USE_MODELTRANSLATION:
    urlpatterns += [
        url('^i18n/$', set_language, name='set_language'),
    ]

urlpatterns += [
    # We don't want to presume how your homepage works, so here are a
    # few patterns you can use to set it up.

    # HOMEPAGE AS STATIC TEMPLATE
    # ---------------------------
    # This pattern simply loads the index.html template. It isn't
    # commented out like the others, so it's the default. You only need
    # one homepage pattern, so if you use a different one, comment this
    # one out.

    url("^$", direct_to_template, {"template": "index.html"}, name="home"),

    # HOMEPAGE AS AN EDITABLE PAGE IN THE PAGE TREE
    # ---------------------------------------------
    # This pattern gives us a normal ``Page`` object, so that your
    # homepage can be managed via the page tree in the admin. If you
    # use this pattern, you'll need to create a page in the page tree,
    # and specify its URL (in the Meta Data section) as "/", which
    # is the value used below in the ``{"slug": "/"}`` part.
    # Also note that the normal rule of adding a custom
    # template per page with the template name using the page's slug
    # doesn't apply here, since we can't have a template called
    # "/.html" - so for this case, the template "pages/index.html"
    # should be used if you want to customize the homepage's template.
    # NOTE: Don't forget to import the view function too!

    # url("^$", mezzanine.pages.views.page, {"slug": "/"}, name="home"),

    # HOMEPAGE FOR A BLOG-ONLY SITE
    # -----------------------------
    # This pattern points the homepage to the blog post listing page,
    # and is useful for sites that are primarily blogs. If you use this
    # pattern, you'll also need to set BLOG_SLUG = "" in your
    # ``settings.py`` module, and delete the blog page object from the
    # page tree in the admin if it was installed.
    # NOTE: Don't forget to import the view function too!

    # url("^$", blog_views.blog_post_list, name="home"),

    # MEZZANINE'S URLS
    # ----------------
    # ADD YOUR OWN URLPATTERNS *ABOVE* THE LINE BELOW.
    # ``mezzanine.urls`` INCLUDES A *CATCH ALL* PATTERN
    # FOR PAGES, SO URLPATTERNS ADDED BELOW ``mezzanine.urls``
    # WILL NEVER BE MATCHED!

    # If you'd like more granular control over the patterns in
    # ``mezzanine.urls``, go right ahead and take the parts you want
    # from it, and use them directly below instead of using
    # ``mezzanine.urls``.
    url("^", include("mezzanine.urls")),

    # MOUNTING MEZZANINE UNDER A PREFIX
    # ---------------------------------
    # You can also mount all of Mezzanine's urlpatterns under a
    # URL prefix if desired. When doing this, you need to define the
    # ``SITE_PREFIX`` setting, which will contain the prefix. Eg:
    # SITE_PREFIX = "my/site/prefix"
    # For convenience, and to avoid repeating the prefix, use the
    # commented out pattern below (commenting out the one above of course)
    # which will make use of the ``SITE_PREFIX`` setting. Make sure to
    # add the import ``from django.conf import settings`` to the top
    # of this file as well.
    # Note that for any of the various homepage patterns above, you'll
    # need to use the ``SITE_PREFIX`` setting as well.

    # ("^%s/" % settings.SITE_PREFIX, include("mezzanine.urls"))

]

# Adds ``STATIC_URL`` to the context of error pages, so that error
# pages can use JS, CSS and images.
handler404 = "mezzanine.core.views.page_not_found"
handler500 = "mezzanine.core.views.server_error"

7.在視圖程式中,撰寫讀取百香果交易行情的程式。(請參閱百香網誌:使用Python和Django設計百香果農產品交易行情網站)

 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
from django.shortcuts import render
from django.template.response import TemplateResponse

# Create your views here.
import requests
import json

def direct_to_template(request, template, extra_context=None, **kwargs):
    """
    Replacement for Django's ``direct_to_template`` that uses
    ``TemplateResponse`` via ``mezzanine.utils.views.render``.
    """
    context = extra_context or {}
    context["params"] = kwargs
    
    for (key, value) in context.items():
        print (key, value)
        if callable(value):
            context[key] = value()
            
    r = requests.get('http://data.coa.gov.tw/Service/OpenData/FromM/FarmTransData.aspx')
    fruits = json.loads(r.text)
    rows = []
    for row in fruits:
        if '百香果' in row['作物名稱']:
            rows.append(row)

    return TemplateResponse(request, template, locals())
#    return TemplateResponse(request, template, context)

8.在樣版程式中選擇適當位置,插入百香果交易行情的模版程式。(請參閱百香網誌:使用Python和Django設計百香果農產品交易行情網站)


  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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
{% extends "base.html" %}
{% load i18n  mezzanine_tags staticfiles%}
{% block meta_title %}{% trans "Home" %}{% endblock %}
{% block title %}{% trans "Home" %}{% endblock %}
{% block breadcrumb_wrapper %}
{% endblock %}

{% block title_wrapper %}
{% endblock %}

{% block breadcrumb_menu %}
<li class="active">{% trans "Home" %}</li>
{% endblock %}


{% block all_content %}
<section id="{% block section_id %}featured{% endblock %}">
{% block left_wrapper %}
{% endblock %}


{% block main_wrapper %}
<div class="col-md-{% block main_col_size %}none{% endblock %} {% block main_class %}{% endblock %}">
{% block main %}


<!-- start slider -->
 <div class="container">
  <div class="row">
   <div class="col-lg-12">
 <!-- Slider -->
        <div id="main-slider" class="flexslider">
            <ul class="slides">
              <li>
                <img src="{% static "img/slides/1.jpg" %}" alt="" />
                <div class="flex-caption">
                    <h3>Modern Design</h3> 
     <p>Duis fermentum auctor ligula ac malesuada. Mauris et metus odio, in pulvinar urna</p> 
     <a href="#" class="btn btn-theme">Learn More</a>
                </div>
              </li>
              <li>
                <img src="{% static "img/slides/2.jpg" %}" alt="" />
                <div class="flex-caption">
                    <h3>Fully Responsive</h3> 
     <p>Sodales neque vitae justo sollicitudin aliquet sit amet diam curabitur sed fermentum.</p> 
     <a href="#" class="btn btn-theme">Learn More</a>
                </div>
              </li>
              <li>
                <img src="{% static "img/slides/3.jpg" %}" alt="" />
                <div class="flex-caption">
                    <h3>Clean & Fast</h3> 
     <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit donec mer lacinia.</p> 
     <a href="#" class="btn btn-theme">Learn More</a>
                </div>
              </li>
            </ul>
        </div>
 <!-- end slider -->
   </div>
  </div>
 </div> 

{% endblock %}
</div>
{% endblock %}
{% block right_wrapper %}
{% endblock %}
</section>
<section class="callaction">
 <div class="container">
  <div class="row">
   <div class="col-lg-12">
    <div class="big-cta">
     <div class="cta-text">
      <h2><span>Moderna</span> Free Mezzanine Business theme</h2>
{% for row in rows %}
{% if forloop.first %}
<table style='width:100%' border='1'>
<caption><h2>百香果市場交易情形</h2></caption>
<tr><th>交易日期</th><th>作物代號</th><th>作物名稱</th><th>市場代碼</th><th>市場名稱</th><th>上價</th><th>中價</th><th>下價</th><th>平均價</th><th>交易量</th></tr>
{% endif %}
<tr>
<td><center>{{ row.交易日期 }}</center></td>
<td><center>{{ row.作物代號 }}</center></td>
<td><center>{{ row.作物名稱 }}</center></td>
<td><center>{{ row.市場代號 }}</center></td>
<td><center>{{ row.市場名稱 }}</center></td>
<td><center>{{ row.上價 }}</center></td>
<td><center>{{ row.中價 }}</center></td>
<td><center>{{ row.下價 }}</center></td>
<td><center>{{ row.平均價 }}</center></td>
<td><center>{{ row.交易量 }}</center></td>
</tr>
{% if forloop.last %}
</table>
{% endif %}
{% endfor %}
     </div>
    </div>
   </div>
  </div>
 </div>
 </section>

<section id="content">
 <div class="container">
  <div class="row">
   <div class="col-lg-12">
    <div class="row">
     <div class="col-lg-3">
      <div class="box">
       <div class="box-gray aligncenter">
        <h4>Fully responsive</h4>
        <div class="icon">
        <i class="fa fa-desktop fa-3x"></i>
        </div>
        <p class="">
         Voluptatem accusantium doloremque laudantium sprea totam rem aperiam.
        </p>
         
       </div>
       <div class="box-bottom">
        <a href="#">Learn more</a>
       </div>
      </div>
     </div>
     <div class="col-lg-3">
      <div class="box">
       <div class="box-gray aligncenter">
        <h4>Modern Style</h4>
        <div class="icon">
        <i class="fa fa-pagelines fa-3x"></i>
        </div>
        <p>
         Voluptatem accusantium doloremque laudantium sprea totam rem aperiam.
        </p>
         
       </div>
       <div class="box-bottom">
        <a href="#">Learn more</a>
       </div>
      </div>
     </div>
     <div class="col-lg-3">
      <div class="box">
       <div class="box-gray aligncenter">
        <h4>Customizable</h4>
        <div class="icon">
        <i class="fa fa-edit fa-3x"></i>
        </div>
        <p>
         Voluptatem accusantium doloremque laudantium sprea totam rem aperiam.
        </p>
         
       </div>
       <div class="box-bottom">
        <a href="#">Learn more</a>
       </div>
      </div>
     </div>
     <div class="col-lg-3">
      <div class="box">
       <div class="box-gray aligncenter">
        <h4>Valid HTML5</h4>
        <div class="icon">
        <i class="fa fa-code fa-3x"></i>
        </div>
        <p>
         Voluptatem accusantium doloremque laudantium sprea totam rem aperiam.
        </p>
         
       </div>
       <div class="box-bottom">
        <a href="#">Learn more</a>
       </div>
      </div>
     </div>
    </div>
   </div>
  </div>
  <!-- divider -->
  <div class="row">
   <div class="col-lg-12">
    <div class="solidline">
    </div>
   </div>
  </div>
  <!-- end divider -->
  <!-- Portfolio Projects -->
  <div class="row">
   <div class="col-lg-12">
    <h4 class="heading">Recent Works</h4>
    <div class="row">
     <section id="projects">
     <ul class="portfolio" id="thumbs">
      <!-- Item Project and Filter Name -->
      <li data-type="web" data-id="id-0" class="col-lg-3 design">
      <div class="item-thumbs">
      <!-- Fancybox - Gallery Enabled - Title - Full Image -->
      <a href="{% static "img/works/1.jpg" %}" title="Work 1" data-fancybox-group="gallery" class="hover-wrap fancybox">
      <span class="overlay-img"></span>
      <span class="overlay-img-thumb font-icon-plus"></span>
      </a>
      <!-- Thumb Image and Description -->
      <img alt="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis elementum odio. Curabitur pellentesque, dolor vel pharetra mollis." src="{% static "img/works/1.jpg" %}">
      </div>
      </li>
      <!-- End Item Project -->
      <!-- Item Project and Filter Name -->
      <li data-type="icon" data-id="id-1" class="item-thumbs col-lg-3 design">
      <!-- Fancybox - Gallery Enabled - Title - Full Image -->
      <a href="{% static "img/works/2.jpg" %}" title="Work 2" data-fancybox-group="gallery" class="hover-wrap fancybox">
      <span class="overlay-img"></span>
      <span class="overlay-img-thumb font-icon-plus"></span>
      </a>
      <!-- Thumb Image and Description -->
      <img alt="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis elementum odio. Curabitur pellentesque, dolor vel pharetra mollis." src="{% static "img/works/2.jpg" %}">
      </li>
      <!-- End Item Project -->
      <!-- Item Project and Filter Name -->
      <li data-type="illustrator" data-id="id-2" class="item-thumbs col-lg-3 photography">
      <!-- Fancybox - Gallery Enabled - Title - Full Image -->
      <a href="{% static "img/works/3.jpg" %}" title="Work 3" data-fancybox-group="gallery" class="hover-wrap fancybox">
      <span class="overlay-img"></span>
      <span class="overlay-img-thumb font-icon-plus"></span>
      </a>
      <!-- Thumb Image and Description -->
      <img alt="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis elementum odio. Curabitur pellentesque, dolor vel pharetra mollis." src="{% static "img/works/3.jpg" %}">
      </li>
      <!-- End Item Project -->
      <!-- Item Project and Filter Name -->
      <li data-type="illustrator" data-id="id-2" class="item-thumbs col-lg-3 photography">
      <!-- Fancybox - Gallery Enabled - Title - Full Image -->
      <a href="{% static "img/works/4.jpg" %}" title="Work 4" data-fancybox-group="gallery" class="hover-wrap fancybox">
      <span class="overlay-img"></span>
      <span class="overlay-img-thumb font-icon-plus"></span>
      </a>
      <!-- Thumb Image and Description -->
      <img alt="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis elementum odio. Curabitur pellentesque, dolor vel pharetra mollis." src="{% static "img/works/4.jpg" %}">
      </li>
      <!-- End Item Project -->
     </ul>
     </section>
    </div>
   </div>
  </div>

 </div>
 </section>

{% endblock %}

10.最後執行結果