若要验证 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 服务器 仅用于 本地开发目的。 但是,部署到 Web 主机时,Django 会改用主机的 Web 服务器。
wsgi.py
Django 项目中的模块负责连接到生产服务器。
如果要使用与默认 8000 不同的端口,只需在命令行上指定端口号,例如 python manage.py runserver 5000
。
Ctrl+click
在 http://127.0.0.1:8000/
VS Code 终端输出窗口中打开该地址的默认浏览器的 URL。 如果 Django 安装正确且项目有效,则会看到如下所示的默认页面。 “VS Code 输出”窗口还显示服务器日志。
创建用于Microsoft广告的 Django 应用
在激活虚拟环境的 VS Code 终端中,在项目文件夹中运行管理实用工具的 startapp
命令, (驻留 manage.py
) :
python manage.py startapp app
命令创建一个名为 app
的文件夹,其中包含大量代码文件和一个子文件夹。 其中,你经常使用 views.py
(,其中包含在 Web 应用中定义页面的函数) ,以及 models.py
包含定义数据对象) 类的 (。
migrations
Django 的管理实用工具使用该文件夹来管理数据库版本,如本教程稍后所述。 还有 (应用配置) 的文件 apps.py
、 admin.py
用于创建管理界面) (,以及 tests.py
用于单元测试) 的 (,此处未介绍这些文件。
在 中添加 app/settings.py
以下代码并设置自己的 CLIENT_ID、 CLIENT_SECRET、 DEVELOPER_TOKEN和 ENVIRONMENT 值。
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
在 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',
在 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
在 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%;
在 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">
<th>Code</th>
<th>ErrorCode</th>
<th>Message</th>
{% for error in errors %}
<td>{{ error.Code }}</td>
<td>{{ error.ErrorCode }}</td>
<td>{{ error.Message }}</td>
{% endfor %}
</table>
</section>
{% 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">
<th>Id</th>
<th>UserName</th>
<th>First Name</th>
<th>Last Name</th>
<td>{{ bingadsuser.Id }}</td>
<td>{{ bingadsuser.UserName }}</td>
<td>{{ bingadsuser.Name.FirstName }}</td>
<td>{{ bingadsuser.Name.LastName }}</td>
</table>
</section>
<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 class="jumbotron">
<section id="accounts">
<h1>Account Details</h1>
<table class="message_list">
<thead>
<th>Id</th>
<th>Name</th>
</thead>
<tbody>
{% for account in accounts %}
<td>{{ account.Id }}</td>
<td>{{ account.Name }}</td>
{% endfor %}
</tbody>
</table>
</section>
{% 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.
</section>
<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><a href="/callback" class="btn btn-primary btn-large">Authenticate Microsoft Account »</a></p>
</section>
{% 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 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 »</a></p>
</section>
{% endif %}
<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 »</a></p>
<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 »</a></p>
<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 »</a></p>
{% endblock %}
{% block scripts %}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'app/site.css' %}"/>
{% endblock %}
在 app/templates/app
文件夹中, layout.html
使用以下内容创建一个文件。
<!DOCTYPE html>
<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>
<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 class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="{% url 'home' %}">Home</a></li>
{% include 'app/loginpartial.html' %}
<div class="container body-content">
{% block content %}{% endblock %}
<footer>
<p>© {{ year }} - My Django Application</p>
</footer>
{% block scripts %}{% endblock %}
</body>
</html>
在 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>
<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 class="form-group">
<label for="id_password" class="col-md-2 control-label">Password</label>
<div class="col-md-10">
{{ form.password }}
<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" />
{% if form.errors %}
<p class="validation-summary-errors">Please enter a correct user name and password.</p>
{% endif %}
</form>
</section>
{% endblock %}
{% block scripts %}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'app/site.css' %}"/>
{% endblock %}
在 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>
</form>
{% else %}
<ul class="nav navbar-nav navbar-right">
<li><a href="{% url 'login' %}">Log in</a></li>
{% endif %}
在 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'}))
修改 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
修改 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
Users = get_user_model()
user = User.objects.get(username=request.user.username)
except User.DoesNotExist:
return render(
request,
'app/index.html'
bingadsuser = user.bingadsuser
except BingAdsUser.DoesNotExist:
bingadsuser = BingAdsUser()
bingadsuser.user = user
# 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=[]
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)
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)
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:
except BingAdsUser.DoesNotExist:
clear_session_data(request)
return render(
request,
'app/index.html'
def user_has_active_session(request):
return True if request.session['is_authenticated'] else False
except KeyError:
return False
def user_has_refresh_token(username):
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
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:
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
将 的内容 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),
使用 Ctrl+K S
保存所有修改的文件。
运行 python manage.py makemigrations
以在迁移文件夹中生成脚本,用于将数据库从当前状态迁移到新状态。
运行 python manage.py migrate
以将脚本应用于实际数据库。 迁移脚本可有效地记录对数据模型所做的所有增量更改, (models.py
随时间推移) 。 通过应用迁移,Django 会更新数据库以匹配模型。 由于每个增量更改都有自己的脚本,因此 Django 可以自动迁移任何以前版本的数据库 (包括新数据库) 到当前版本。 因此,只需关注 models.py 中的模型,而不要关注基础数据库架构或迁移脚本。 你让 Django 做那个部分!
通过在虚拟环境的 VS Code 中打开终端,然后运行 命令 python manage.py createsuperuser --username=<username> --email=<email>
(当然)将 和 <email>
替换为<username>
你的个人信息,在应用中创建一个超级用户帐户。 运行命令时,Django 会提示输入并确认密码。
请务必记住用户名和密码组合。 这些是用于在 Web 应用的管理门户中进行身份验证的凭据。
在 VS Code 终端中,在激活虚拟环境的情况下,使用 python manage.py runserver
运行开发服务器并打开浏览器 http://127.0.0.1:8000/
以查看呈现“Hello, Django”的页面。
在 Web 浏览器中,转到 http://127.0.0.1:8000/admin/
“ 用户”下创建新的 Django Web 用户。 这不同于Microsoft广告用户凭据,因此多个Microsoft广告用户可以单独登录到你的应用。
单击“ Microsoft帐户身份验证 ”后,系统会提示授予自己的 Web 应用管理Microsoft广告帐户的权限。 如果你同意,并且你有权访问Microsoft广告帐户,则应重定向到帐户名称的视图, () 和 ID () 。
通过必应广告 API 开始使用 Python