共用方式為


逐步解說:Python 中的 Bing 廣告 API Web 應用程式

本教學課程會探索如何使用Bing Ads Python SDKVisual Studio Code IDE 和Django Web 架構開始執行 Microsoft Advertising Web 應用程式。

本教學課程不會探索 Django 本身的各種詳細資料,例如使用資料模型和建立系統管理介面。 如需這些層面的指引,請參閱 Django 檔。 如需如何在 VS Code 終端機、編輯器和偵錯工具中使用 Django 的詳細資訊,請參閱在 Visual Studio Code 中使用 Django。 本教學課程非常依賴在Visual Studio Code 中使用 Django 中的設定指示。

範例 Web 應用程式概觀

在本教學課程結束時,您將會在 上 http://localhost 執行 Web 應用程式,以驗證您的 Microsoft Advertising 使用者認證,並顯示您的使用者和帳戶資訊。 然後,您可以新增多個 Web 應用程式使用者,這些使用者可以啟用應用程式的存取權,以使用其 Microsoft Advertising 認證。 此 Web 應用程式提供 Web 應用程式使用者的一對一對應,例如 ContosoUser 與 Microsoft Advertising 使用者。 如需如何修改資料模型的資訊,請參閱 Django 檔 以取得詳細資訊。 如果您的 Web 應用程式使用者能夠使用 Microsoft 帳戶存取其 Microsoft Advertising 帳戶,重新整理權杖會儲存在網頁伺服器上的 SQL Lite 資料庫中。

必要條件

您必須安裝Visual Studio Code,才能遵循本教學課程。 若要執行 Django Web 應用程式,您可以使用Visual Studio Community或Visual Studio Professional;不過,設定步驟會與本教學課程中的步驟不同。

必須從 python.org安裝 Python 3;通常會使用頁面上第一個顯示的 [下載 Python 3.7.0 ] 按鈕 (或是最新版本) 。 在 Windows 上,確定您的 PATH 環境變數中包含 Python 解譯器的位置。 您可以在命令提示字元中執行 來檢查。 path 如果未包含 Python 解譯器的資料夾,請開啟 [Windows 設定],搜尋「環境」,選取 [編輯您帳戶的環境變數],然後編輯 Path 變數以包含該資料夾。

您必須 安裝Bing Ads Python SDK,本教學課程將逐步引導您完成安裝。

您將需要安裝 Django Web 架構 ,才能在本機部署應用程式,而本教學課程將逐步引導您完成安裝。

您至少需要一位具有 Microsoft Advertising 認證和 開發人員權杖的使用者。

您必須註冊應用程式,並記下用戶端識別碼 (已註冊的應用程式識別碼) 和用戶端密碼 (已註冊的密碼) 。 在此範例中,您必須註冊非原生) 的 Web 應用程式 (。 系統會要求您註冊一或多個重新導向 URL,而在本教學課程中,您應該註冊 http://localhost/callback 。 當部署到生產伺服器時,您應該改用 HTTPs 。 如需註冊應用程式和授權碼授與流程的詳細資訊,請參閱 使用 OAuth 進行驗證

本教學課程是在 Windows 上開發。 雖然 Windows 不需要執行範例,但如果您使用其他作業系統,例如 Linux 或 MacOS,下列部分步驟會有所不同。

建立 Django 的專案環境

在本節中,您會建立 Django 安裝所在的虛擬環境。 使用虛擬環境可避免將 Django 安裝到全域 Python 環境中,並讓您完全控制應用程式中使用的程式庫。

  1. 在您的檔案系統上,建立本教學課程的專案資料夾,例如 hello_django

  2. 在 資料夾中 hello_django ,開啟 Powershell 或您慣用的腳本殼層,並使用下列命令,根據您目前的解譯器建立名為 的 env 虛擬環境:

    py -3 -m venv env
    
  3. hello_django執行 ,或執行 VS Code 並使用[檔案> 開啟資料夾] 命令,在 VS Code code .中開啟專案資料夾

    開啟 VS Code

  4. 在 VS Code 中,開啟命令選擇區 (檢視>命令選擇區Ctrl+Shift+P) 。 然後選取 [Python:選取解譯器 ] 命令。

  5. 命令會顯示 VS Code 可以自動尋找的可用解譯器清單。 您的清單會有所不同;如果您沒有看到所需的解譯器,請參閱設定 Python 環境。 從清單中,選取專案資料夾中開頭為 ./env.\env 的虛擬環境:

    選取 Python 的虛擬環境

  6. 執行 終端機:新的終端 機 (Ctrl+Shift+ ` 從命令選擇區) ,這會建立終端機,並藉由執行其啟用腳本來自動啟用虛擬環境。

    注意事項

    在 Windows 上,如果您的預設終端機類型是 PowerShell,您可能會看到無法執行 activate.ps1 的錯誤,因為系統上已停用執行中的腳本。 此錯誤應該會提供如何允許腳本的相關資訊連結。 否則,請使用 終端機:選取 [預設殼層 ] 以設定您慣用的預設值。

    選取的環境會出現在 VS Code 狀態列的左下角。 請注意 (venv) 指示器,指出您使用的是虛擬環境:

    在 VS Code 狀態列中顯示的選取環境

  7. 在 VS Code 終端機中透過 pip 在虛擬環境中安裝 Django:

    python -m pip install django
    
  8. 透過 VS Code 終端機中的 pip,在虛擬環境中安裝 Bing Ads Python SDK:

    python -m pip install bingads
    

您現在已準備好撰寫 Django 和 Microsoft Advertising 程式碼的自封式虛擬環境。

建立和執行 Django 應用程式

在 Django 術語中,「Django 專案」是由數個月臺層級組態檔,以及您部署至 Web 主機以建立完整 Web 應用程式的一或多個「應用程式」所組成。 Django 專案可以包含多個應用程式,每個應用程式在專案中通常都有獨立的函式,而相同的應用程式可以位於多個 Django 專案中。 應用程式本身只是遵循 Django 預期之特定慣例的 Python 套件。

若要建立 Django 應用程式,則必須先建立 Django 專案作為應用程式的容器,然後建立應用程式本身。 基於這兩個目的,您會使用 Django 系統管理公用程式 , django-admin 當您安裝 Django 套件時會安裝此公用程式。

建立 Django 專案

  1. 在虛擬環境啟動所在的 VS Code 終端機中,執行下列命令:

    django-admin startproject web_project .
    

    startproject 命令假設 (在結尾使用 . ,) 目前的資料夾是您的專案資料夾,並在其中建立下列專案:

    • manage.py:專案的 Django 命令列系統管理公用程式。 您可以使用 python manage.py <command> [options] 執行專案的系統管理命令。

    • 名為 的 web_project 子資料夾,其中包含下列檔案:

      • __init__.py:空的檔案,告知 Python 此資料夾是 Python 套件。
      • wsgi.py:WSGI 相容網頁伺服器的進入點,可為您的專案提供服務。 您通常會將此檔案保持原樣,因為它會為生產 Web 服務器提供勾點。
      • settings.py:包含 Django 專案的設定,您可以在開發 Web 應用程式的過程中修改這些設定。
      • urls.py:包含 Django 專案的目錄,您也會在開發過程中加以修改。

      Django Web 專案

  2. 若要確認 Django 專案,請確定您的虛擬環境已啟用,然後使用 命令 python manage.py runserver 啟動 Django 的開發伺服器。 伺服器會在預設埠 8000 上執行,而您會在 VS Code 終端機輸出視窗中看到如下的輸出:

    Performing system checks...
    
    System check identified no issues (0 silenced).
    
    You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
    Run 'python manage.py migrate' to apply them.
    October 18, 2018 - 05:38:23
    Django version 2.1.2, using settings 'web_project.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CTRL-BREAK.
    

    當您第一次執行伺服器時,它會在 檔案 db.sqlite3 中建立預設的 SQLite 資料庫,這通常適用于開發用途,但可用於低磁片區 Web 應用程式的生產環境。 此外,Django 的內建網頁伺服器 供本機開發之用。 不過,當您部署至 Web 主機時,Django 會改用主機的網頁伺服器。 wsgi.pyDjango 專案中的模組會負責連結至生產伺服器。

    如果您想要使用與預設 8000 不同的埠,只要在命令列上指定埠號碼,例如 python manage.py runserver 5000

  3. Ctrl+clickhttp://127.0.0.1:8000/VS Code 終端機輸出視窗中的 URL,以開啟該位址的預設瀏覽器。 如果 Django 已正確安裝且專案有效,您會看到如下所示的預設頁面。 [VS Code 輸出] 視窗也會顯示伺服器記錄檔。

    空白 Django 專案的預設檢視

  4. 當您完成時,請關閉瀏覽器視窗,並停止 Ctrl+C VS Code 中的伺服器,如 VS Code 終端機輸出視窗中所示。

建立 Microsoft Advertising 的 Django 應用程式

  1. 在已啟用虛擬環境的 VS Code 終端機中,在專案資料夾中執行系統管理公用程式的 startapp 命令, (位於 manage.py) :

    python manage.py startapp app
    

    命令會建立名為 app 的資料夾,其中包含一些程式碼檔案和一個子資料夾。 其中,您經常會使用 views.py 包含函式的 (,這些函式會定義 Web 應用程式) 中的頁面,以及 models.py 包含定義資料物件) 之類別的 (。 Django 的系統管理公用程式會使用 此 migrations 資料夾來管理資料庫版本,如本教學課程稍後所述。 另外還有應用程式組態) (檔案 apps.pyadmin.py 建立系統管理介面) 的 (,以及 tests.py 單元測試) 的 (,但這裡未涵蓋。

  2. 在 中 app/settings.py 新增下列程式碼,並設定您自己的 CLIENT_IDCLIENT_SECRETDEVELOPER_TOKENENVIRONMENT 值。

    """
    Bing Ads API settings
    Edit with your credentials.
    """
    
    REDIRECTION_URI = "http://localhost:8000/callback"
    CLIENT_ID = "ClientIdGoesHere" # Your registered App ID
    CLIENT_SECRET="ClientSecretGoesHere" # Your registered App Password
    DEVELOPER_TOKEN = "DeveloperTokenGoesHere" # Your production developer token
    ENVIRONMENT = 'production'
    API_VERSION=13
    
  3. 在 中 app/settings.py ,將 新 app 增至已安裝的應用程式清單。

        INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app',
    ]
    
  4. 在 VS Code 終端機中, app/static/app 建立 和 app/templates/app 資料夾:

    (env) PS C:\dev\hello_django> mkdir app/static/app
    (env) PS C:\dev\hello_django> mkdir app/templates/app 
    
  5. 在 資料夾中 app/static/app 建立名為 site.css 的新檔案,並新增下列內容。

    .message {
        font-weight: 600;
        color: blue;
    }
    
    .message_list th,td {
        text-align: left;
        padding-right: 15px;
    }
    
    .navbar {
        background-color: lightslategray;
        font-size: 1em;
        font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
        color: white;
        padding: 8px 5px 8px 5px;
    }
    
    .navbar a {
        text-decoration: none;
        color: inherit;
    }
    
    .navbar-brand {
        font-size: 1.2em;
        font-weight: 600;
    }
    
    .navbar-item {
        font-variant: small-caps;
        margin-left: 30px;
    }
    
    .body-content {
        padding: 5px;
        font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }
    
    input[name=message] {
        width: 80%;
    }
    
  6. 在 檔 app/templates/app 夾內建立檔案, index.html 其中包含下列內容。

    {% extends "app/layout.html" %}
    {% block content %}
    {% if errors %}
    <div class="jumbotron">
        <section id="errors">
            <h1>Errors occurred in your last request to Bing Ads API.</h1>
            <table class="message_list">
                <tr>
                    <th>Code</th>
                    <th>ErrorCode</th>
                    <th>Message</th>
                </tr>
                {% for error in errors %}
                <tr>
                    <td>{{ error.Code }}</td> 
                    <td>{{ error.ErrorCode }}</td> 
                    <td>{{ error.Message }}</td> 
                </tr>
                {% endfor %}
            </table> 
        </section>
    </div>
    {% endif %}
    {% if user.is_authenticated  %}
    {% if bingadsuser  %}
    <div class="jumbotron">
        <section id="enabled">
            <h1>Your credentials have access to Microsoft Advertising.</h1>
            <table class="message_list">
                <tr>
                    <th>Id</th>
                    <th>UserName</th>
                    <th>First Name</th>
                    <th>Last Name</th>
                </tr>
                <tr>
                    <td>{{ bingadsuser.Id }}</td> 
                    <td>{{ bingadsuser.UserName }}</td> 
                    <td>{{ bingadsuser.Name.FirstName }}</td> 
                    <td>{{ bingadsuser.Name.LastName }}</td> 
                </tr>
            </table>  
        </section>
    </div>
    <div class="jumbotron">
        <section id="revoke">
            <p class="lead">Click here to revoke access for this app to your Microsoft Advertising accounts. You will then be able to login with a different Microsoft Advertising user. </p>
            <form id="revokeForm" action="/revoke" method="post" class="navbar-left">
                {% csrf_token %}
                <p><a href="javascript:document.getElementById('revokeForm').submit()" class="btn btn-primary btn-large">Delete Refresh Token</a></p>
            </form>
        </section>
    </div>
    <div class="jumbotron">
        <section id="accounts">        
            <h1>Account Details</h1>
            <table class="message_list">
                <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th> 
                </tr>
                </thead>
                <tbody>
                {% for account in accounts %}
                <tr>
                    <td>{{ account.Id }}</td>
                    <td>{{ account.Name }}</td> 
                </tr>
                {% endfor %}
                </tbody>
            </table> 
        </section>
    </div>
    {% else  %}
    <div class="jumbotron">
        <section id="enable">
            <h1>Enable Microsoft Advertising Access</h1>
            <p class="lead">
                You are logged into the Django web application, but not yet signed in with your Microsoft Advertising credentials. 
                You can sign in with Microsoft Advertising credentials below.
            </p>
        </section>
    </div>
    <div>
        <div class="col-md-6">
            <section id="socialLoginForm">
                <h1>Microsoft Account Login</h1>
                <p class="lead">
                    Click here to authenticate your Microsoft Account. 
                    If you don't have Microsoft Advertising credentials, you can go to the 
                    <a href="https://ads.microsoft.com/customer/Signup.aspx">Microsoft Advertising Sign Up</a> page.
                </p>
                <p><a href="/callback" class="btn btn-primary btn-large">Authenticate Microsoft Account &raquo;</a></p>
            </section>
        </div>    
    </div>
    {% endif %}
    {% else %}
    <div class="jumbotron">
        <div class="col-md-6">
            <section id="socialLoginForm">
                <h1>Microsoft Advertising Example Web Application</h1>
                <p class="lead">
                    Before you can provide your Microsoft Advertising user credentials and access Microsoft Advertising data, 
                    you must <a href="{% url 'login' %}">login</a> to the Django web application.
                </p>
                <p class="lead">Use your site's Django admin portal to add web app users.</p>
                <p><a href="/admin" class="btn btn-primary btn-large">Django Admin &raquo;</a></p>
            </section>
        </div>    
    </div>
    {% endif %}
    <div>
        <div class="col-md-4">
            <h2>Get Started Using Python with Bing Ads API</h2>
            <p>The Bing Ads Python Software Development Kit (SDK) simplifies workflows such as OAuth authentication and report file parsing.</p>
            <p><a class="btn btn-default" href="https://learn.microsoft.com/advertising/guides/get-started-python">Learn more &raquo;</a></p>
        </div>
        <div class="col-md-4">
            <h2>Django</h2>
            <p>Django is a free web framework for building Web sites and Web applications using HTML, CSS and JavaScript.</p>
            <p><a class="btn btn-default" href="https://www.djangoproject.com/">Learn more &raquo;</a></p>
        </div>
        <div class="col-md-4">
            <h2>Microsoft Azure</h2>
            <p>You can publish your web app to Microsoft Azure. Find out how you can host your application with a free trial today.</p>
            <p><a class="btn btn-default" href="https://azure.microsoft.com">Learn more &raquo;</a></p>
        </div>
    </div>
    {% endblock %}
    {% block scripts %}
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'app/site.css' %}"/>
    {% endblock %}
    
  7. 在 檔 app/templates/app 夾內建立檔案, layout.html 其中包含下列內容。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{ title }} - My Django Application</title>
        {% load static %}
        <link rel="stylesheet" type="text/css" href="{% static 'app/site.css' %}"/>
        <script src="{% static 'app/scripts/modernizr-2.6.2.js' %}"></script>
    </head>
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a href="/" class="navbar-brand">Microsoft Advertising App via Django</a>
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="{% url 'home' %}">Home</a></li>
                    </ul>
                    {% include 'app/loginpartial.html' %}
                </div>
            </div>
        </div>
        <div class="container body-content">
    {% block content %}{% endblock %}
            <hr/>
            <footer>
                <p>&copy; {{ year }} - My Django Application</p>
            </footer>
        </div>
    {% block scripts %}{% endblock %}
    </body>
    </html>
    
  8. 在 檔 app/templates/app 夾內建立檔案, login.html 其中包含下列內容。

    {% extends "app/layout.html" %}
    {% block content %}
    <h2>{{ title }}</h2>
    <div class="row">
        <div class="col-md-8">
            <section id="loginForm">
                <form action="." method="post" class="form-horizontal">
                    {% csrf_token %}
                    <h4>Use a local account to log in.</h4>
                    <hr />
                    <div class="form-group">
                        <label for="id_username" class="col-md-2 control-label">User name</label>
                        <div class="col-md-10">
                            {{ form.username }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_password" class="col-md-2 control-label">Password</label>
                        <div class="col-md-10">
                            {{ form.password }}
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-offset-2 col-md-10">
                            <input type="hidden" name="next" value="/" />
                            <input type="submit" value="Log in" class="btn btn-default" />
                        </div>
                    </div>
                    {% if form.errors %}
                    <p class="validation-summary-errors">Please enter a correct user name and password.</p>
                    {% endif %}
                </form>
            </section>
        </div>
    </div>
    {% endblock %}
    {% block scripts %}
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'app/site.css' %}"/>
    {% endblock %}
    
  9. 在 檔 app/templates/app 夾內建立檔案, loginpartial.html 其中包含下列內容。

    {% if user.is_authenticated  %}
    <form id="logoutForm" action="/applogout" method="post" class="navbar-right">
        {% csrf_token %}
        <ul class="nav navbar-nav navbar-right">
            <li><span class="navbar-brand">Hello {{ user.username }}!</span></li>
            <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
        </ul>
    </form>
    {% else %}
    <ul class="nav navbar-nav navbar-right">
        <li><a href="{% url 'login' %}">Log in</a></li>
    </ul>
    {% endif %}
    
  10. 在 檔 app 夾內建立檔案, forms.py 其中包含下列內容。

    from django import forms
    from django.contrib.auth.forms import AuthenticationForm
    from django.utils.translation import ugettext_lazy as _
    
    class BootstrapAuthenticationForm(AuthenticationForm):
        """Authentication form which uses boostrap CSS."""
        username = forms.CharField(max_length=254,
                                   widget=forms.TextInput({
                                       'class': 'form-control',
                                       'placeholder': 'User name'}))
        password = forms.CharField(label=_("Password"),
                                   widget=forms.PasswordInput({
                                       'class': 'form-control',
                                       'placeholder':'Password'}))
    
  11. 修改 app/models.py 以符合下列程式碼。

    from django.db import models
    from django.contrib.auth.models import User
    
    # In this web app a Microsoft Advertising user maps a Django web user to a refresh token.
    
    class BingAdsUser(models.Model):
        user = models.OneToOneField(User, on_delete=models.PROTECT)
        refresh_token = models.CharField(max_length=200)
    
        # def __unicode__(self):              # __unicode__ on Python 2
        #     return self.refresh_token
        def __str__(self):              # __str__ on Python 3
            return self.refresh_token
    
  12. 修改 app/views.py 以符合下列程式碼。

    from django.http import HttpRequest, HttpResponse
    from django.shortcuts import render
    from django.template.loader import get_template, render_to_string
    from web_project import settings
    from datetime import datetime
    from django.shortcuts import redirect
    from django.contrib.auth import authenticate, login, logout, get_user_model
    from django.contrib.auth.models import User
    from app.models import BingAdsUser
    from bingads import *
    
    # import logging
    # logging.basicConfig(level=logging.INFO)
    # logging.getLogger('suds.client').setLevel(logging.DEBUG)
    # logging.getLogger('suds.transport').setLevel(logging.DEBUG)
    
    authorization_data = AuthorizationData(
        account_id=None, 
        customer_id=None, 
        developer_token=None, 
        authentication=None)
    
    customer_service=None
    
    def home(request):
        """
        If an authenticated user returns to this page after logging in, the appropriate 
        context is provided to index.html for rendering the page. 
        """
        assert isinstance(request, HttpRequest)
    
        # If the Django user has a refresh token stored, 
        # try to use it to get Microsoft Advertising data.
        if user_has_refresh_token(request.user.username):
            return redirect('/callback')
        else:
            return render(
                request,
                'app/index.html'
            )
    
    def callback(request):
        """Handles OAuth authorization, either via callback or direct refresh request."""
        assert isinstance(request, HttpRequest)
    
        authentication = OAuthWebAuthCodeGrant(
            client_id=settings.CLIENT_ID,
            client_secret=settings.CLIENT_SECRET, 
            redirection_uri=settings.REDIRECTION_URI,
            env=settings.ENVIRONMENT)
    
        return authorize_bing_ads_user(request, authentication)
    
    def authorize_bing_ads_user(request, authentication):
        assert isinstance(request, HttpRequest)
    
        global customer_service
        bingadsuser = None
    
        try:
            Users = get_user_model()
            user = User.objects.get(username=request.user.username)
        except User.DoesNotExist:
            return render(
                request,
                'app/index.html'
            )
    
        try:
            bingadsuser = user.bingadsuser
        except BingAdsUser.DoesNotExist:
            bingadsuser = BingAdsUser()
            bingadsuser.user = user
            pass
    
        try:
            # If we have a refresh token let's refresh the access token.
            if(bingadsuser is not None and bingadsuser.refresh_token != ""):
                authentication.request_oauth_tokens_by_refresh_token(bingadsuser.refresh_token)
                bingadsuser.refresh_token = authentication.oauth_tokens.refresh_token
    
            # If the current HTTP request is a callback from the Microsoft Account authorization server,
            # use the current request url containing authorization code to request new access and refresh tokens.
            elif (request.GET.get('code') is not None):
                authentication.request_oauth_tokens_by_response_uri(response_uri = request.get_full_path()) 
                bingadsuser.refresh_token = authentication.oauth_tokens.refresh_token
        except OAuthTokenRequestException:
            bingadsuser.refresh_token = ""  
    
        user.save()
        bingadsuser.save()
    
        # If there is no refresh token saved and no callback from the authorization server, 
        # then connect to the authorization server and request user consent.
        if (bingadsuser.refresh_token == ""):
            return redirect(authentication.get_authorization_endpoint())
    
        set_session_data(request, authentication)
    
        # At this point even if the user has valid Django web application credentials, 
        # we don't know whether they have access to Microsoft Advertising.
        # Let's test to see if they can call Bing Ads API service operations. 
    
        bing_ads_user = None
        accounts=[]
        errors=[]
    
        try:
            bing_ads_user = get_user(None)
            accounts = search_accounts_by_user_id(bing_ads_user.Id)['AdvertiserAccount']
        except WebFault as ex:
            errors=get_webfault_errors(ex)
            pass
    
        context = {
            'bingadsuser': bing_ads_user,
            'accounts': accounts,
            'errors': errors,
        }
        return render(
            request,
            'app/index.html',
            context
        )
    
    def revoke(request):
        """Deletes the refresh token for the user authenticated in the current session."""
        assert isinstance(request, HttpRequest)
    
        try:
            Users = get_user_model()
            user = User.objects.get(username=request.user.username)
            bingadsuser = user.bingadsuser
            if(bingadsuser is not None):
                bingadsuser.refresh_token = ""
                bingadsuser.save()
        except User.DoesNotExist:
            pass
        except BingAdsUser.DoesNotExist:
            pass
    
        clear_session_data(request)
    
        return render(
            request,
            'app/index.html'
        )
    
    def user_has_active_session(request):
        try:
            return True if request.session['is_authenticated'] else False 
        except KeyError:
            return False
    
    def user_has_refresh_token(username):
        try:
            Users = get_user_model()
            user = User.objects.get(username=username)
            bingadsuser = user.bingadsuser
            if(bingadsuser is not None and bingadsuser.refresh_token != ""):
                return True
        except User.DoesNotExist:
            return False
        except BingAdsUser.DoesNotExist:
            return False
    
    def set_session_data(request, authentication):
        global authorization_data
        global customer_service
    
        try:
            request.session['is_authenticated'] = True
    
            authorization_data.authentication = authentication
            authorization_data.developer_token = settings.DEVELOPER_TOKEN
    
            customer_service = ServiceClient(
                service='CustomerManagementService', 
                version=settings.API_VERSION,
                authorization_data=authorization_data,
                environment=settings.ENVIRONMENT
            )
    
        except KeyError:
            pass
        return None   
    
    def clear_session_data(request):
        global authorization_data
        global customer_service
    
        request.session['is_authenticated'] = False
    
        authorization_data = AuthorizationData(account_id=None, customer_id=None, developer_token=None, authentication=None)
        customer_service = None
    
    def applogout(request):
        logout(request)
        clear_session_data(request)
        return redirect('/')
    
    def get_user(user_id):
        ''' 
        Gets a Microsoft Advertising User object by the specified user ID.
    
        :param user_id: The Microsoft Advertising user identifier.
        :type user_id: long
        :return: The Microsoft Advertising user.
        :rtype: User
        '''
        global customer_service
    
        return customer_service.GetUser(UserId = user_id).User
    
    def search_accounts_by_user_id(user_id):
        ''' 
        Search for account details by UserId.
    
        :param user_id: The Microsoft Advertising user identifier.
        :type user_id: long
        :return: List of accounts that the user can manage.
        :rtype: Dictionary of AdvertiserAccount
        '''
    
        predicates={
            'Predicate': [
                {
                    'Field': 'UserId',
                    'Operator': 'Equals',
                    'Value': user_id,
                },
            ]
        }
    
        accounts=[]
    
        page_index = 0
        PAGE_SIZE=100
        found_last_page = False
    
        while (not found_last_page):
            paging=set_elements_to_none(customer_service.factory.create('ns5:Paging'))
            paging.Index=page_index
            paging.Size=PAGE_SIZE
            search_accounts_response = customer_service.SearchAccounts(
                PageInfo=paging,
                Predicates=predicates
            )
    
            if search_accounts_response is not None and hasattr(search_accounts_response, 'AdvertiserAccount'):
                accounts.extend(search_accounts_response['AdvertiserAccount'])
                found_last_page = PAGE_SIZE > len(search_accounts_response['AdvertiserAccount'])
                page_index += 1
            else:
                found_last_page=True
    
        return {
            'AdvertiserAccount': accounts
        }
    
    def set_elements_to_none(suds_object):
        for (element) in suds_object:
            suds_object.__setitem__(element[0], None)
        return suds_object
    
    def get_webfault_errors(ex):
        errors=[]
    
        if not hasattr(ex.fault, "detail"):
            raise Exception("Unknown WebFault")
    
        error_attribute_sets = (
            ["ApiFault", "OperationErrors", "OperationError"],
            ["AdApiFaultDetail", "Errors", "AdApiError"],
            ["ApiFaultDetail", "BatchErrors", "BatchError"],
            ["ApiFaultDetail", "OperationErrors", "OperationError"],
            ["EditorialApiFaultDetail", "BatchErrors", "BatchError"],
            ["EditorialApiFaultDetail", "EditorialErrors", "EditorialError"],
            ["EditorialApiFaultDetail", "OperationErrors", "OperationError"],
        )
    
        for error_attribute_set in error_attribute_sets:
            errors = get_api_errors(ex.fault.detail, error_attribute_set)
            if errors is not None:
                return errors
    
        return None
    
    def get_api_errors(error_detail, error_attribute_set):
        api_errors = error_detail
        for field in error_attribute_set:
            api_errors = getattr(api_errors, field, None)
        if api_errors is None:
            return None
    
        errors=[]
        if type(api_errors) == list:
            for api_error in api_errors:
                errors.append(api_error)
        else:
            errors.append(api_errors)
        return errors
    
  13. 將 的內容 web_project/urls.py 取代為下列內容。 檔案 urls.py 是您指定模式的位置,可將不同的 URL 路由傳送至其適當的檢視。 例如,下列程式碼會將應用程式的根 URL ("") 對應至 home 您剛才新增至 的函式 app/views.py

    from django.contrib import admin
    from django.urls import path
    from app import views as app_views
    from django.contrib.auth import views as auth_views
    from datetime import datetime
    from django.conf.urls import include, url
    from app.forms import BootstrapAuthenticationForm
    from django.contrib.auth.views import HttpResponseRedirect
    
    from django.contrib import admin
    admin.autodiscover()
    
    urlpatterns = [
        url(r'^applogout', app_views.applogout, name='applogout'),
        url(r'^callback', app_views.callback, name='callback'),
        url(r'^revoke', app_views.revoke, name='revoke'),
        url(r'^$', app_views.home, name='home'),
        url(r'^login/$',
            auth_views.LoginView.as_view(
                template_name='app/login.html', 
                authentication_form=BootstrapAuthenticationForm,
                extra_context= {
                    'title':'Log in',
                    'year':datetime.now().year,
                }
            ),
            name='login'),
        url(r'^logout$',
            auth_views.LogoutView.as_view(),
            {
                'next_page': '/',
            },
            name='logout'),
    
        url(r'^admin/', admin.site.urls),
    ]
    
  14. 使用 儲存所有修改過的 Ctrl+K S 檔案。

  15. 執行 python manage.py makemigrations 以在移轉資料夾中產生腳本,以將資料庫從其目前狀態移轉至新狀態。

  16. 執行 python manage.py migrate 以將腳本套用至實際資料庫。 移轉腳本會有效地記錄您對資料模型所做的所有累加式變更, (models.py) 一段時間。 藉由套用移轉,Django 會更新資料庫以符合您的模型。 因為每個累加式變更都有自己的腳本,所以 Django 可以自動移轉任何舊版的資料庫 (包括新資料庫) 至目前的版本。 因此,您只需要在 models.py 中考慮模型,而不需要使用基礎資料庫架構或移轉腳本。 您讓 Django 執行該部分!

  17. 在應用程式中建立超級使用者帳戶,方法是在 VS Code 中為您的虛擬環境開啟終端機,然後執行 命令 python manage.py createsuperuser --username=<username> --email=<email> ,當然將 和 <email> 取代 <username> 為您的個人資訊。 當您執行命令時,Django 會提示您輸入並確認密碼。

    重要事項

    請務必記住您的使用者名稱和密碼組合。 這些是您在 Web 應用程式的管理入口網站中用來驗證的認證。

  18. 在 VS Code 終端機中,再次啟動虛擬環境,使用 執行開發伺服器 python manage.py runserver ,然後開啟瀏覽器以 http://127.0.0.1:8000/ 查看轉譯 「Hello, Django」 的頁面。

  19. 在網頁瀏覽器中,移至 http://127.0.0.1:8000/admin/ [使用者] 底下建立新的 Django Web 使用者。 這與您的 Microsoft Advertising 使用者認證不同,因此多個 Microsoft Advertising 使用者可以個別登入您的應用程式。

    Django 管理員

  20. 使用新使用者登入 (不是超級系統管理員) ,您應該會看到使用 Microsoft 帳戶進行驗證的選項。

    驗證 Microsoft 帳戶

  21. 按一下 [ 驗證 Microsoft 帳戶 ] 之後,系統會提示您授與自己的 Web 應用程式許可權,以管理您的 Microsoft Advertising 帳戶。 如果您同意,而且您有 Microsoft Advertising 帳戶的存取權,則應該將您重新導向至帳戶名稱的檢視, () 和識別碼 () 。

另請參閱

開始搭配 Bing 廣告 API 使用 Python