Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b561761

Browse files
author
chenyumic
authored
Added Django sample for App Engine Python 3.7 standard runtime (GoogleCloudPlatform#1720)
* Added Django sample for App Engine Python 3.7 runtime. * Added README * Minor fix. * Minor fixes. * Minor fixes. * Added main.py.
1 parent c6f0f38 commit b561761

File tree

20 files changed

+385
-0
lines changed

20 files changed

+385
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This file specifies files that are *not* uploaded to Google Cloud Platform
2+
# using gcloud. It follows the same syntax as .gitignore, with the addition of
3+
# "#!include" directives (which insert the entries of the given .gitignore-style
4+
# file at that point).
5+
#
6+
# For more information, run:
7+
# $ gcloud topic gcloudignore
8+
#
9+
.gcloudignore
10+
# If you would like to upload your .git directory, .gitignore file or files
11+
# from your .gitignore file, remove the corresponding line
12+
# below:
13+
.git
14+
.gitignore
15+
16+
# Python pycache:
17+
__pycache__/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Getting started with Django on Google Cloud Platform on App Engine Standard
2+
3+
[![Open in Cloud Shell][shell_img]][shell_link]
4+
5+
[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
6+
[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/standard_python37/django/README.md
7+
8+
This repository is an example of how to run a [Django](https://www.djangoproject.com/)
9+
app on Google App Engine Standard Environment. It uses the
10+
[Writing your first Django app](https://docs.djangoproject.com/en/2.1/intro/tutorial01/) as the
11+
example app to deploy.
12+
13+
14+
# Tutorial
15+
See our [Running Django in the App Engine Standard Environment](https://cloud.google.com/python/django/appengine) tutorial for instructions for setting up and deploying this sample application.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# [START django_app]
2+
runtime: python37
3+
4+
handlers:
5+
# This configures Google App Engine to serve the files in the app's static
6+
# directory.
7+
- url: /static
8+
static_dir: static_files/
9+
10+
# This handler routes all requests not caught above to your main app. It is
11+
# required when static routes are defined, but can be omitted (along with
12+
# the entire handlers section) when there are no static files defined.
13+
- url: /.*
14+
script: auto
15+
# [END django_app]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from mysite.wsgi import application
2+
3+
# App Engine by default looks for a main.py file at the root of the app
4+
# directory with a WSGI-compatible object called app.
5+
# This file imports the WSGI-compatible object of your Django app,
6+
# application from mysite/wsgi.py and renames it app so it is discoverable by
7+
# App Engine without additional configuration.
8+
# Alternatively, you can add a custom entrypoint field in your app.yaml:
9+
# entrypoint: gunicorn -b :$PORT mysite.wsgi
10+
app = application
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env python
2+
import os
3+
import sys
4+
5+
if __name__ == '__main__':
6+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
7+
try:
8+
from django.core.management import execute_from_command_line
9+
except ImportError as exc:
10+
raise ImportError(
11+
"Couldn't import Django. Are you sure it's installed and "
12+
"available on your PYTHONPATH environment variable? Did you "
13+
"forget to activate a virtual environment?"
14+
) from exc
15+
execute_from_command_line(sys.argv)

appengine/standard_python37/django/mysite/__init__.py

Whitespace-only changes.
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
Django settings for mysite project.
3+
4+
Generated by 'django-admin startproject' using Django 2.1.1.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/2.1/topics/settings/
8+
9+
For the full list of settings and their values, see
10+
https://docs.djangoproject.com/en/2.1/ref/settings/
11+
"""
12+
13+
import os
14+
15+
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17+
18+
19+
# Quick-start development settings - unsuitable for production
20+
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
21+
22+
# SECURITY WARNING: keep the secret key used in production secret!
23+
# Update the secret key to a value of your own before deploying the app.
24+
SECRET_KEY = 'lldtg$9(wi49j_hpv8nnqlh!cj7kmbwq0$rj7vy(b(b30vlyzj'
25+
26+
# SECURITY WARNING: don't run with debug turned on in production!
27+
DEBUG = True
28+
29+
# SECURITY WARNING: App Engine's security features ensure that it is safe to
30+
# have ALLOWED_HOSTS = ['*'] when the app is deployed. If you deploy a Django
31+
# app not on App Engine, make sure to set an appropriate host here.
32+
# See https://docs.djangoproject.com/en/2.1/ref/settings/
33+
ALLOWED_HOSTS = ['*']
34+
35+
36+
# Application definition
37+
38+
INSTALLED_APPS = [
39+
'polls.apps.PollsConfig',
40+
'django.contrib.admin',
41+
'django.contrib.auth',
42+
'django.contrib.contenttypes',
43+
'django.contrib.sessions',
44+
'django.contrib.messages',
45+
'django.contrib.staticfiles',
46+
]
47+
48+
MIDDLEWARE = [
49+
'django.middleware.security.SecurityMiddleware',
50+
'django.contrib.sessions.middleware.SessionMiddleware',
51+
'django.middleware.common.CommonMiddleware',
52+
'django.middleware.csrf.CsrfViewMiddleware',
53+
'django.contrib.auth.middleware.AuthenticationMiddleware',
54+
'django.contrib.messages.middleware.MessageMiddleware',
55+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
56+
]
57+
58+
ROOT_URLCONF = 'mysite.urls'
59+
60+
TEMPLATES = [
61+
{
62+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
63+
'DIRS': [],
64+
'APP_DIRS': True,
65+
'OPTIONS': {
66+
'context_processors': [
67+
'django.template.context_processors.debug',
68+
'django.template.context_processors.request',
69+
'django.contrib.auth.context_processors.auth',
70+
'django.contrib.messages.context_processors.messages',
71+
],
72+
},
73+
},
74+
]
75+
76+
WSGI_APPLICATION = 'mysite.wsgi.application'
77+
78+
79+
# Database
80+
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
81+
82+
# [START db_setup]
83+
if os.getenv('GAE_APPLICATION', None):
84+
# Running on production App Engine, so connect to Google Cloud SQL using
85+
# the unix socket at /cloudsql/<your-cloudsql-connection string>
86+
DATABASES = {
87+
'default': {
88+
'ENGINE': 'django.db.backends.mysql',
89+
'HOST': '/cloudsql/[YOUR-CONNECTION-NAME]',
90+
'USER': '[YOUR-USERNAME]',
91+
'PASSWORD': '[YOUR-PASSWORD]',
92+
}
93+
}
94+
else:
95+
# Running locally so connect to either a local MySQL instance or connect to
96+
# Cloud SQL via the proxy. To start the proxy via command line:
97+
#
98+
# $ cloud_sql_proxy -instances=[INSTANCE_CONNECTION_NAME]=tcp:3306
99+
#
100+
# See https://cloud.google.com/sql/docs/mysql-connect-proxy
101+
DATABASES = {
102+
'default': {
103+
'ENGINE': 'django.db.backends.mysql',
104+
'HOST': '127.0.0.1',
105+
'PORT': '3306',
106+
'NAME': '[YOUR-DATABASE]',
107+
'USER': '[YOUR-USERNAME]',
108+
'PASSWORD': '[YOUR-PASSWORD]',
109+
}
110+
}
111+
# [END db_setup]
112+
113+
114+
# Password validation
115+
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
116+
117+
AUTH_PASSWORD_VALIDATORS = [
118+
{
119+
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
120+
},
121+
{
122+
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
123+
},
124+
{
125+
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
126+
},
127+
{
128+
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
129+
},
130+
]
131+
132+
133+
# Internationalization
134+
# https://docs.djangoproject.com/en/2.1/topics/i18n/
135+
136+
LANGUAGE_CODE = 'en-us'
137+
138+
TIME_ZONE = 'UTC'
139+
140+
USE_I18N = True
141+
142+
USE_L10N = True
143+
144+
USE_TZ = True
145+
146+
147+
# Static files (CSS, JavaScript, Images)
148+
# https://docs.djangoproject.com/en/2.1/howto/static-files/
149+
150+
STATIC_ROOT = 'static'
151+
STATIC_URL = '/static/'
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""mysite URL Configuration
2+
3+
The `urlpatterns` list routes URLs to views. For more information please see:
4+
https://docs.djangoproject.com/en/2.1/topics/http/urls/
5+
Examples:
6+
Function views
7+
1. Add an import: from my_app import views
8+
2. Add a URL to urlpatterns: path('', views.home, name='home')
9+
Class-based views
10+
1. Add an import: from other_app.views import Home
11+
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12+
Including another URLconf
13+
1. Import the include() function: from django.urls import include, path
14+
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15+
"""
16+
from django.contrib import admin
17+
from django.urls import include, path
18+
19+
urlpatterns = [
20+
path('', include('polls.urls')),
21+
path('admin/', admin.site.urls),
22+
]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
WSGI config for mysite project.
3+
4+
It exposes the WSGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.wsgi import get_wsgi_application
13+
14+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
15+
16+
application = get_wsgi_application()

appengine/standard_python37/django/polls/__init__.py

Whitespace-only changes.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.contrib import admin
2+
3+
from .models import Question, Choice
4+
5+
admin.site.register(Question)
6+
admin.site.register(Choice)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class PollsConfig(AppConfig):
5+
name = 'polls'
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import datetime
2+
3+
from django.db import models
4+
from django.utils import timezone
5+
6+
7+
class Question(models.Model):
8+
question_text = models.CharField(max_length=200)
9+
pub_date = models.DateTimeField('date published')
10+
11+
def __str__(self):
12+
return self.question_text
13+
14+
def was_published_recently(self):
15+
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
16+
17+
18+
class Choice(models.Model):
19+
question = models.ForeignKey(Question, on_delete=models.CASCADE)
20+
choice_text = models.CharField(max_length=200)
21+
votes = models.IntegerField(default=0)
22+
23+
def __str__(self):
24+
return self.choice_text
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<h1>{{ question.question_text }}</h1>
2+
3+
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
4+
5+
<form action="{% url 'polls:vote' question.id %}" method="post">
6+
{% csrf_token %}
7+
{% for choice in question.choice_set.all %}
8+
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
9+
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
10+
{% endfor %}
11+
<input type="submit" value="Vote">
12+
</form>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% if latest_question_list %}
2+
<ul>
3+
{% for question in latest_question_list %}
4+
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
5+
{% endfor %}
6+
</ul>
7+
{% else %}
8+
<p>No polls are available.</p>
9+
{% endif %}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<h1>{{ question.question_text }}</h1>
2+
3+
<ul>
4+
{% for choice in question.choice_set.all %}
5+
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
6+
{% endfor %}
7+
</ul>
8+
9+
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.test import TestCase
2+
3+
# Create your tests here.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django.urls import path
2+
3+
from . import views
4+
5+
app_name = 'polls'
6+
urlpatterns = [
7+
path('', views.IndexView.as_view(), name='index'),
8+
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
9+
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
10+
path('<int:question_id>/vote/', views.vote, name='vote'),
11+
]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from django.http import HttpResponse, HttpResponseRedirect
2+
from django.shortcuts import get_object_or_404 ,render
3+
from django.urls import reverse
4+
from django.views import generic
5+
6+
from .models import Choice, Question
7+
8+
9+
class IndexView(generic.ListView):
10+
template_name = 'polls/index.html'
11+
context_object_name = 'latest_question_list'
12+
13+
def get_queryset(self):
14+
"""Return the last five published questions."""
15+
return Question.objects.order_by('-pub_date')[:5]
16+
17+
18+
class DetailView(generic.DetailView):
19+
model = Question
20+
template_name = 'polls/detail.html'
21+
22+
23+
class ResultsView(generic.DetailView):
24+
model = Question
25+
template_name = 'polls/results.html'
26+
27+
def vote(request, question_id):
28+
question = get_object_or_404(Question, pk=question_id)
29+
try:
30+
selected_choice = question.choice_set.get(pk=request.POST['choice'])
31+
except (KeyError, Choice.DoesNotExist):
32+
# Redisplay the question voting form.
33+
return render(request, 'polls/detail.html', {
34+
'question': question,
35+
'error_message': "You didn't select a choice.",
36+
})
37+
else:
38+
selected_choice.votes += 1
39+
selected_choice.save()
40+
# Always return an HttpResponseRedirect after successfully dealing
41+
# with POST data. This prevents data from being posted twice if a
42+
# user hits the Back button.
43+
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

0 commit comments

Comments
 (0)