2016/11/07

[Python] VS2013 預設的 Django 專案修改紀錄

剛開始用VS2013玩 Django Web專案, 才發現開啟了一連串的災難, 為避免忘記, 還是做個紀錄好了.

環境說明:
1. 因原本電腦就裝了 Python3.4版, 所以一開始建環境時選的就是 Python3.4.
2. 建立完 Virtual Environment後, 顯示 Django 1.10.3 版, pip 1.5.6 版, setuptools 2.1 版.

問題處理:
  1. 當裝完 Virtual Environment 後, VS 會出現 [Synchronize the Database] 的說明頁, 要開發人員去點選一個 [Django Sync DB…] 的功能.
    執行後出現以下的訊息:
    Executing manage.py syncdb
    Unknown command: 'syncdb'
    Type 'manage.py help' for usage.
    The Python REPL process has exited
    原因: syncdb 指令已在 django1.7 後過期.
    解決方式:
    改使用 python manage.py migrate 指令:
    Step1. 在專案上按右鍵, 點選 [Open Command Prompt Here…], 開啟一個命令列提示視窗.
    Step2. 輸入 python manage.py migrate 後按下 Enter.
    Step3. 第一次執行後會出現錯誤訊息, 大致如下:

    File "c:\test\TestDjangoWebProject\TestDjangoWebProject\urls.py", line 6, in <module>
        from django.conf.urls import patterns, url
    ImportError: cannot import name 'patterns'

  2. 承1., 可以發現問題在 urls.py 這個檔案, 所以打開這個檔案看看:
    c:\test\TestDjangoWebProject\TestDjangoWebProject\TestDjangoWebProject\urls.py
    原因: django.conf.urls.patterns() 在 Django1.10 版本已移除.
    解決方式: 改寫如下
    """
    Definition of urls for TestDjangoWebProject.
    """
    from datetime import datetime
    # 移除 patterns 的 import
    from django.conf.urls import url
    from app.forms import BootstrapAuthenticationForm
    # import 必要的 views 宣告
    from app.views import home, contact, about
    from django.contrib.auth.views import login, logout

    # Uncomment the next lines to enable the admin:
    # from django.conf.urls import include
    # from django.contrib import admin
    # admin.autodiscover()

    # 不用 patterns(), 改為 tuple 寫法
    urlpatterns = [
        # Examples:
        url(r'^$', home, name='home'),
        url(r'^contact$', contact, name='contact'),
        url(r'^about', about, name='about'),
        url(r'^login/$',
            login,
            {
                'template_name': 'app/login.html',
                'authentication_form': BootstrapAuthenticationForm,
                'extra_context':
                {
                    'title':'Log in',
                    'year':datetime.now().year,
                }
            },
            name='login'),
        url(r'^logout$',
            logout,
            {
                'next_page': '/',
            },
            name='logout'),
        # Uncomment the admin/doc line below to enable admin documentation:
        # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
        # Uncomment the next line to enable the admin:
        # url(r'^admin/', include(admin.site.urls)),
    ]
    修改並儲存後, 在命令列提式視窗中再執行一次 python manage.py migrate 指令, 沒問題的話應該可以正常執行完畢.
  3. 試著執行看看, 一開始網頁會出現以下的錯誤訊息:

    TypeError at /

    render() got an unexpected keyword argument 'context_instance'
    Request Method: GET
    Request URL: http://localhost:51622/
    Django Version: 1.10.3
    Exception Type: TypeError
    Exception Value: render() got an unexpected keyword argument 'context_instance'
    Exception Location: c:\test\TestDjangoWebProject\TestDjangoWebProject\app\views.py in home, line 19
    原因: render_to_response 中的 context_instance 參數在 Django1.10 版已移除.
    解決方式: 打開 c:\test\TestDjangoWebProject\TestDjangoWebProject\app\views.py, 改寫如下
    """
    Definition of views.
    """
    from django.shortcuts import render
    from django.http import HttpRequest
    from django.template import RequestContext
    from datetime import datetime
    def home(request):
        """Renders the home page."""
        assert isinstance(request, HttpRequest)
        return render(
            request,
            'app/index.html',
            {'context' : RequestContext(request,
              {
                  'title':'Home Page',
                  'year':datetime.now().year,
              })}
        )
    def contact(request):
        """Renders the contact page."""
        assert isinstance(request, HttpRequest)
        return render(
            request,
            'app/contact.html',
            {'context' : RequestContext(request,
              {
                  'title':'Contact',
                  'message':'Your contact page.',
                  'year':datetime.now().year,
              })}
        )
    def about(request):
        """Renders the about page."""
        assert isinstance(request, HttpRequest)
        return render(
            request,
            'app/about.html',
            {'context' : RequestContext(request,
              {
                  'title':'About',
                  'message':'Your application description page.',
                  'year':datetime.now().year,
              })}
        )
  4. 承3., 再執行一次, 會發現網頁的錯誤訊息已經改了.

    TemplateDoesNotExist at /

    app/index.html
    Request Method: GET
    Request URL: http://localhost:51622/
    Django Version: 1.10.3
    Exception Type: TemplateDoesNotExist
    Exception Value: app/index.html
    Exception Location: c:\test\TestDjangoWebProject\TestDjangoWebProject\env\lib\site-packages\django\template\loader.py in get_template, line 25
    原因: 找不到 view 的檔案. TEMPLATE_DIRS 的設定在 Django1.8 後已經被 TEMPLATES 取代.
    解決方式: 雖然問題看起來是在 loader.py 這個檔案, 但實際上要改的是 c:\test\TestDjangoWebProject\TestDjangoWebProject\TestDjangoWebProject\settings.py .
    所以打開 settings.py 檔案, 找尋 TEMPLATE_DIRS 的設定. 將 TEMPLATE_DIRS 設定改為如下的方式:
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [path.join(PROJECT_ROOT, 'app/templates/').replace('\\', '/')],
        },
    ]
    改完並儲存後, 再執行一次應該就能看到網頁.
  5. 承4., 如果細心一點會發現執行後的命令視窗會出現一段 WARNINGS.
    WARNINGS:
    ?: (1_8.W001) The standalone TEMPLATE_* settings were deprecated in Django 1.8 and the TEMPLATES dictionary takes precedence. You must put the values of the following settings into your default TEMPLATES dict: TEMPLATE_DEBUG, TEMPLATE_LOADERS.
    要避掉這個 WARNINGS, 需要再調整兩個地方.
    *TEMPLATE_DEBUG: 將 settings.py 檔案中的 TEMPLATE_DEBUG 移除, 改放到 TEMPLATES 裡.
    *TEMPLATE_LOADERS: 將 settings.py 檔案中的 TEMPLATE_LOADERS 移除.
    詳細的 TEMPLATE_LOADERS 設定可以參考: Upgrading templates to Django 1.8
    要注意, 如果有設定了 'APP_DIRS' 屬性為 True, 就不能在 'OPTIONS' 裡再設定 'loaders'. 最後設定起來的 TEMPLATES 如下:
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [path.join(PROJECT_ROOT, 'app/templates/').replace('\\', '/')],
            'OPTIONS': {
                'debug': DEBUG,
                'loaders': [
                    'django.template.loaders.filesystem.Loader',
                    'django.template.loaders.app_directories.Loader',
                    ]
            },
        },

沒有留言:

張貼留言