Procedura dettagliata: applicazione Web API di Bing Ads in Python

Questa esercitazione illustra come iniziare a eseguire un'applicazione Web Microsoft Advertising utilizzando l'SDK Python di Bing Ads, l'IDE Visual Studio Code e il framework Web Django .

Questo tutorial non esplora vari dettagli su Django stesso, come il lavoro con i modelli di dati e la creazione di un'interfaccia amministrativa. Per indicazioni su questi aspetti, fare riferimento alla documentazione di Django. Per ulteriori dettagli su come lavorare con Django nel terminale, nell'editor e nel debugger di VS Code, vedi Usare Django in Visual Studio Code. Questo tutorial prende in prestito molto dalle istruzioni di configurazione in Usare Django in Visual Studio Code.

Panoramica dell'applicazione Web di esempio

Al termine di questa esercitazione, sarà in esecuzione http://localhost un'applicazione Web che autenticherà le credenziali utente di Microsoft Advertising e visualizzerà le informazioni su utente e account. È quindi possibile aggiungere più utenti dell'applicazione Web, che possono abilitare l'accesso per l'applicazione per l'utilizzo delle proprie credenziali di Microsoft Advertising. Questa applicazione Web fornisce un mapping uno-a-uno di un utente di un'applicazione Web, ad esempio ContosoUser, a un utente di Microsoft Advertising. Per informazioni su come modificare il modello di dati, vedere la documentazione di Django per ulteriori informazioni. Se l'utente dell'applicazione Web consente l'accesso ai propri account Microsoft Advertising con un account Microsoft, un token di aggiornamento viene archiviato nel database SQL Lite nel server Web.

Prerequisiti

Per seguire questa esercitazione, dovrai avere installato Visual Studio Code . Per eseguire l'app Web Django, è possibile usare Visual Studio Community o Visual Studio Professional; tuttavia, i passaggi di configurazione variano rispetto a quelli di questa esercitazione.

Dovrai avere Python 3 installato da python.org; in genere utilizza il pulsante Scarica Python 3.7.0 che appare per primo nella pagina (o qualunque sia l'ultima versione). In Windows, assicurati che la posizione del tuo interprete Python sia inclusa nella variabile di ambiente PATH. È possibile eseguire questo controllo al path prompt dei comandi. Se la cartella dell'interprete Python non è inclusa, apri le Impostazioni di Windows, cerca "ambiente", seleziona Modifica variabili di ambiente per il tuo account, quindi modifica la variabile Path per includere tale cartella.

Dovrai installarel'SDK Python di Bing Ads e questo tutorial ti guiderà attraverso l'installazione.

È necessario installare il framework Web Django per distribuire l'applicazione in locale e questo tutorial ti guiderà attraverso l'installazione.

Avrai bisogno di almeno un utente con credenziali di Microsoft Advertising e un token di sviluppo.

È necessario registrare un'applicazione e prendere nota dell'ID client (ID applicazione registrato) e del segreto client (password registrata). Per questo esempio è necessario registrare un'app Web (non nativa). Ti verrà chiesto di registrare uno o più URL di reindirizzamento e per questo tutorial dovresti registrarti http://localhost/callback. È invece consigliabile usare https quando viene distribuito in un server di produzione. Per ulteriori dettagli sulla registrazione di un'applicazione e sul flusso di concessione del codice di autorizzazione, vedere Autenticazione con OAuth.

Questa esercitazione è stata sviluppata su Windows. Anche se Windows non è necessario per eseguire l'esempio, alcuni dei passaggi seguenti variano se si usa un altro sistema operativo, ad esempio Linux o MacOS.

Creare un ambiente di progetto per Django

In questa sezione viene creato un ambiente virtuale in cui è installato Django. L'uso di un ambiente virtuale evita di installare Django in un ambiente Python globale e ti dà il controllo esatto sulle librerie utilizzate in un'applicazione.

  1. Nel file system, crea una cartella di progetto per questa esercitazione, ad esempio hello_django.

  2. Nella cartella, aprire Powershell o la shell dello script preferito e usare il comando seguente per creare un ambiente virtuale denominato env in base all'interprete hello_django corrente:

    py -3 -m venv env
    
  3. Apri la cartella del hello_django progetto in VS Code eseguendo code ., oppure eseguendo VS Code e utilizzando il comando File>Open Folder .

    Apri VS Code

  4. In VS Code, aprire il Riquadro comandi (Riquadro comandi Visualizza> o Ctrl+Shift+P). Quindi seleziona il comando Python: Seleziona interprete .

  5. Il comando presenta un elenco di interpreti disponibili che VS Code può individuare automaticamente. La tua lista varierà; se non vedi l'interprete desiderato, vedi Configurazione degli ambienti Python. Dall'elenco, selezionare l'ambiente virtuale nella cartella del progetto che inizia con ./env o .\env:

    Selezione dell'ambiente virtuale per Python

  6. Esegui terminale: Nuovo terminale (Ctrl+Shift+ ` ) dal riquadro comandi, che crea un terminale e attiva automaticamente l'ambiente virtuale eseguendo il suo script di attivazione.

    Nota

    In Windows, se il tipo di terminale predefinito è PowerShell, potrebbe essere visualizzato un errore che indica che non è possibile eseguire activate.ps1 perché l'esecuzione degli script è disabilitata nel sistema. L'errore dovrebbe fornire un collegamento per informazioni su come consentire gli script. In caso contrario, usa Terminale: Seleziona Shell predefinita per impostare l'impostazione predefinita preferita.

    L'ambiente selezionato viene visualizzato nell'angolo inferiore sinistro della barra di stato VS Code. Si noti l'indicatore (venv) che indica che si sta utilizzando un ambiente virtuale:

    Ambiente selezionato visualizzato nella barra di stato di VS Code

  7. Installare Django nell'ambiente virtuale tramite pip nel terminale VS Code:

    python -m pip install django
    
  8. Installare Python SDK di Bing Ads nell'ambiente virtuale tramite pip nel terminale VS Code:

    python -m pip install bingads
    

Ora hai un ambiente virtuale autonomo pronto per la scrittura di codice Django e Microsoft Advertising.

Creare ed eseguire un'app Django

Nella terminologia Django, un "progetto Django" è composto da diversi file di configurazione a livello di sito insieme a una o più "app" che vengono distribuite in un host Web per creare un'applicazione Web completa. Un progetto Django può contenere più app, ognuna delle quali ha in genere una funzione indipendente nel progetto, e la stessa app può trovarsi in più progetti Django. Un'app, da parte sua, è solo un pacchetto Python che segue determinate convenzioni che Django si aspetta.

Per creare un'app Django, quindi, è necessario creare prima il progetto Django che funga da contenitore per l'app, quindi creare l'app stessa. Per entrambi gli scopi si usa l'utilità di amministrazione Django, django-adminche viene installata quando si installa il pacchetto Django.

Creare il progetto Django

  1. Nel terminale VS Code in cui è attivato l'ambiente virtuale, esegui il comando seguente:

    django-admin startproject web_project .
    

    Questo startproject comando presuppone (utilizzando alla fine) che la cartella corrente sia la cartella del . progetto e crea quanto segue al suo interno:

    • manage.py: l'utilità amministrativa della riga di comando di Django per il progetto. I comandi amministrativi per il progetto vengono eseguiti utilizzando python manage.py <command> [options].

    • Una sottocartella denominata web_project, che contiene i file seguenti:

      • __init__.py: un file vuoto che dice a Python che questa cartella è un pacchetto Python.
      • wsgi.py: un punto di ingresso per server Web compatibili con WSGI per servire il progetto. In genere lasci questo file così com'è in quanto fornisce gli hook per i server Web di produzione.
      • settings.py: contiene le impostazioni per il progetto Django, che vengono modificate durante lo sviluppo di un'applicazione web.
      • urls.py: contiene un sommario per il progetto Django, che puoi anche modificare nel corso dello sviluppo.

      Progetto Web Django

  2. Per verificare il progetto Django, assicurati che il tuo ambiente virtuale sia attivato, quindi avvia il server di sviluppo di Django utilizzando il comando python manage.py runserver. Il server viene eseguito sulla porta predefinita 8000 e viene visualizzato un output simile al seguente nella finestra di output del terminale 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.
    

    Quando si esegue il server per la prima volta, viene creato un database SQLite predefinito nel file db.sqlite3, che in genere è destinato a scopi di sviluppo, ma può essere usato in produzione per applicazioni Web a basso volume. Inoltre, il server web integrato di Django è destinato solo a scopi di sviluppo locale. Quando esegui la distribuzione in un host Web, tuttavia, Django utilizza invece il server Web dell'host. Il wsgi.py modulo del progetto Django si occupa di agganciarsi ai server di produzione.

    Se si desidera utilizzare una porta diversa da quella predefinita 8000, è sufficiente specificare il numero di porta nella riga di comando, ad esempio python manage.py runserver 5000.

  3. Ctrl+click l'URL http://127.0.0.1:8000/ nella finestra di output del terminale VS Code per aprire il browser predefinito a tale indirizzo. Se Django è installato correttamente e il progetto è valido, viene visualizzata la pagina predefinita mostrata di seguito. La finestra Output di VS Code mostra anche il registro del server.

    Visualizzazione predefinita del progetto Django vuoto

  4. Al termine, chiudi la finestra del browser e arresta il server in VS Code come Ctrl+C indicato nella finestra di output del terminale VS Code.

Creare un'app Django per Microsoft Advertising

  1. Nel terminale VS Code con l'ambiente virtuale attivato, eseguire il comando dell'utilità di gestione nella cartella del startapp progetto (dove manage.py si trova):

    python manage.py startapp app
    

    Il comando crea una cartella chiamata app che contiene una serie di file di codice e una sottocartella. Di questi, lavori frequentemente ( views.py che contiene le funzioni che definiscono le pagine nella tua app web) e models.py (che contiene classi che definiscono i tuoi oggetti dati). La migrations cartella viene utilizzata dall'utilità di amministrazione di Django per gestire le versioni del database, come discusso più avanti in questo tutorial. Ci sono anche i file apps.py (configurazione dell'app), admin.py (per la creazione di un'interfaccia amministrativa) e tests.py (per gli unit test), che non sono trattati qui.

  2. All'interno app/settings.py aggiungi il codice seguente e imposta i tuoi valori CLIENT_ID, CLIENT_SECRET, DEVELOPER_TOKEN e AMBIENTE .

    """
    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. All'interno app/settings.py di aggiungi app all'elenco delle app installate.

        INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app',
    ]
    
  4. Nel terminale VS Code crea le app/static/app cartelle and app/templates/app :

    (env) PS C:\dev\hello_django> mkdir app/static/app
    (env) PS C:\dev\hello_django> mkdir app/templates/app 
    
  5. All'interno delle app/static/app cartelle crea un nuovo file chiamato site.css e aggiungi il seguente contenuto.

    .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. All'interno della app/templates/app cartella crea un file con index.html il contenuto seguente.

    {% 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. All'interno della app/templates/app cartella crea un file con layout.html il contenuto seguente.

    <!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. All'interno della app/templates/app cartella crea un file con login.html il contenuto seguente.

    {% 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. All'interno della app/templates/app cartella crea un file con loginpartial.html il contenuto seguente.

    {% 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. All'interno della app cartella crea un file con forms.py il contenuto seguente.

    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. Modificarla app/models.py in base al codice seguente.

    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. Modificarla app/views.py in base al codice seguente.

    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. Sostituisci il contenuto di con il contenuto seguente web_project/urls.py . Il urls.py file consente di specificare i modelli per instradare i diversi URL alle visualizzazioni appropriate. Ad esempio, il codice seguente esegue il home mapping dell'URL radice dell'app ("") alla funzione appena aggiuntaapp/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. Salva tutti i file modificati con Ctrl+K S.

  15. Eseguire python manage.py makemigrations per generare script nella cartella migrations che eseguono la migrazione del database dallo stato corrente al nuovo stato.

  16. Eseguire python manage.py migrate per applicare gli script al database effettivo. Gli script di migrazione registrano in modo efficace tutte le modifiche incrementali apportate ai modelli di dati (models.py) nel tempo. Applicando le migrazioni, Django aggiorna il database in modo che corrisponda ai tuoi modelli. Poiché ogni modifica incrementale ha il proprio script, Django può migrare automaticamente qualsiasi versione precedente di un database (incluso un nuovo database) alla versione corrente. Di conseguenza, è necessario preoccuparsi solo dei modelli in models.py, mai dello schema di database sottostante o degli script di migrazione. Hai lasciato che Django facesse quella parte!

  17. Crea un account superutente nell'app aprendo un Terminale in VS Code per il tuo ambiente virtuale, quindi eseguendo il comando python manage.py createsuperuser --username=<username> --email=<email>, sostituendo <username> e <email>, ovviamente, con le tue informazioni personali. Quando esegui il comando, Django ti chiede di inserire e confermare la tua password.

    Importante

    Assicurarsi di ricordare la combinazione di nome utente e password. Si tratta delle credenziali usate per eseguire l'autenticazione nel portale di amministrazione dell'app Web.

  18. Nel terminale VS Code, sempre con l'ambiente virtuale attivato, esegui il server di sviluppo e python manage.py runserver apri un browser per http://127.0.0.1:8000/ visualizzare una pagina che esegue il rendering "Hello, Django".

  19. Nel browser web, vai su http://127.0.0.1:8000/admin/ e crea un nuovo utente web Django in Utenti. Si tratta di un valore distinto dalle credenziali utente di Microsoft Advertising, in modo che più utenti di Microsoft Advertising possano accedere separatamente all'app.

    Amministrazione

  20. Accedere con il nuovo utente (non con privilegi avanzati) e dovrebbe essere visualizzata l'opzione per eseguire l'autenticazione con un account Microsoft.

    Autenticare l'account Microsoft

  21. Dopo aver fatto clic su Autentica account Microsoft , verrà richiesto di concedere alle proprie app Web le autorizzazioni per la gestione degli account Microsoft Advertising. Se si acconsente e si ha accesso agli account Microsoft Advertising, si deve essere reindirizzati a una visualizzazione dei nomi e degli ID degli account.

Vedere anche

Introduzione all'uso di Python con l'API di Bing Ads