Статьи

Использование Django с Appengine

Около

Добро пожаловать в учебник по Django для интеграции с Appengine. Это порт учебника по Django для использования appengine вместо Pure Django. Как и в учебнике по Django, мы создаем механизм опроса, где вы можете создавать опросы, а другие могут голосовать за них. Вместо четырех частей учебника по Django, мы используем только один учебник. Кроме того, так как многие части Django, особенно его супер интерфейс администратора, не работают, мы будем обходить их. Я предполагаю, что вы хорошо знаете Python. Однако я не предполагаю, что у вас был предыдущий опыт работы с Django. Понятия Джанго объяснены.

Что мы будем строить

Мы создадим механизм опроса, где люди смогут создавать опросы и голосовать за варианты. По сути это имеет четыре типа страниц,

  1. Список недавно созданных опросов.
  2. Страница, на которой вы можете создавать новые страницы.
  3. Страница с вариантами выбора и для голосования.
  4. Страница с результатами.

Прямую установку этого можно увидеть на blogango.appspot.com Полный источник этого можно скачать здесь

Загрузка Django и Appengine

Загрузка Django очень хорошо документирована, поэтому я не буду повторять это здесь. А вы уже скачали Appengine , верно? Хотя загрузка Django не требуется для этого урока, так как appengien имеет встроенный django 0.96.

Получать помощь

Если у вас возникли проблемы с этим учебником, обратитесь на форум Django, и кто-нибудь из сообщества Django сможет вам помочь, или оставьте комментарий в блоге 42topics.com , и я постараюсь вам помочь.

Создание проекта

Создайте каталог, в котором вы хотели бы хранить все свои файлы Appengine и Django. Внутри этого каталога выполните команду:

django-admin.py startproject appproject

Это создаст каталог с именем appproject, который будет содержать файлы, используемые Django. Мы рассмотрим эти файлы чуть позже, но перед этим нам нужно создать еще два файла. Создайте файл с именем main.py на том же уровне, что и папка appproject , и поместите этот код:

import os,sys
os.environ['DJANGO_SETTINGS_MODULE'] = 'appproject.settings'

# Google App Engine imports.
from google.appengine.ext.webapp import util

# Force Django to reload its settings.
from django.conf import settings
settings._target = None

import django.core.handlers.wsgi
import django.core.signals
import django.db
import django.dispatch.dispatcher

# Log errors.
#django.dispatch.dispatcher.connect(
# log_exception, django.core.signals.got_request_exception)

# Unregister the rollback event handler.
django.dispatch.dispatcher.disconnect(
django.db._rollback_on_exception,
django.core.signals.got_request_exception)

def main():
# Create a Django application for WSGI.
application = django.core.handlers.wsgi.WSGIHandler()

# Run the WSGI CGI handler with that application.
util.run_wsgi_app(application)

if __name__ == '__main__':
main()

Создайте еще один файл с именем app.yaml и вставьте этот код:

application: appproject
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
script: main.py

В двух предыдущих файлах Appengine рассказала кое-что о нашем приложении и попросила его использовать django для обработки запросов. Строка url: /.* — это регулярное выражение, сообщающее main.py, что нужно обрабатывать запросы с любым URL. Линии:

def main():
# Create a Django application for WSGI.
application = django.core.handlers.wsgi.WSGIHandler()

# Run the WSGI CGI handler with that application.
util.run_wsgi_app(application)

Создайте сервер Django wsgi и делегируйте запросы этому серверу.


Перейдите в папку appproject и выполните команду ::

python manage.py startapp myapp

manage.py — это файл, которыйсоздал django-admin.py . Он содержит команды для управления вашими приложениями Django. python manage.py startapp myapp создает папку, в которой вы будете хранить все свои файлы, относящиеся к этому приложению. В этом каталоге есть еще один интересный файл settings.py . Это содержит настройки, которые для вашего проекта.

Редактирование файла settings.py

Основное различие между чистым Django и Django + Appengine — это ORM. Appengine не хранит данные на традиционном сервере баз данных. Таким образом, Django ORM не будет работать с Appengine. Многие приложения, связанные с Django, в частности, admin , auth и session , не будут работать. django-admin.py startproject appproject создал файл settings.py, предполагая, что вы захотите использовать приложения. Нам нужно удалить эти приложения из settings.py.

Отредактируйте файл settings.py так, чтобы MIDDLEWARE_CLASSES и INSTALLED_APPS выглядели так:

MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
)

INSTALLED_APPS = (
'appproject.poll'
)

Также нам нужно указать Django, где найти файлы HTML, которые могут служить основой для отображения страниц. Измените TEMPLATE_DIRS, чтобы он выглядел так:

import os
ROOT_PATH = os.path.dirname(__file__)
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or
# "C:/www/django/templates". Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
ROOT_PATH + '/templates',
)

Это говорит Django найти шаблоны HTML в каталоге относительно текущего каталога с именем templates .

Напишите файл конфигурации URL

Django использует регулярные выражения, чтобы указать, какая функция должна обрабатывать данный URL. Отредактируйте файл urls.py так:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
(r'^$', 'pollango.poll.views.index'),
(r'^create/$', 'pollango.poll.views.create'),
(r'^poll/(?P<poll_key>[^\.^/]+)/$', 'pollango.poll.views.poll_detail'),
(r'^poll/(?P<poll_key>[^\.^/]+)/results/$', 'pollango.poll.views.poll_results'),
)

У нас есть четыре разных типа страниц, и каждая из этих страниц соответствует конкретной странице. Позволяет disect линию (г '^ $', 'pollango.poll.views.index') . Регулярное выражение r '^ $' отображается в корень сайта ( ^ отображается на начало URL-адреса, а $ — на конец. Таким образом, URL без лишних битов будет обрабатываться этой строкой. 'Pollango.poll. views.index ' , сообщает функции, используемой при вызове этого URL.

Симларли (r '^ create / $', 'pollango.poll.views.create') сообщает, что URL-адрес, содержащий \ create \, должен обрабатываться функцией. pollango.poll.views.create .

Напишите файл models.py.

Вам нужно определить свою модель данных в файле models.py. Для нас две сущности — это опрос, где мы будем хранить вопрос об опросе, и выбор, где мы будем хранить связанные варианты. Итак, давайте напишем файл models.py как:

from google.appengine.ext import db

class Poll(db.Model):
question = db.StringProperty()
created_on = db.DateTimeProperty(auto_now_add = 1)
created_by = db.UserProperty()

def __str__(self):
return '%s' %self.question

def get_absolute_url(self):
return '/poll/%s/' % self.key()


class Choice(db.Model):
poll = db.ReferenceProperty(Poll)
choice = db.StringProperty()
votes = db.IntegerProperty(default = 0)

Позволяет нам разобрать модель данных для опроса:

class Poll(db.Model):
question = db.StringProperty()
created_on = db.DateTimeProperty(auto_now_add = 1)
created_by = db.UserProperty()

Каждая компания должна расширить « google.appengine.ext.db.Model , так что он может быть сохранен в в хранилище, так `` Poll расширяет его. Каждый из атрибутов сущности должен иметь тип « google.appengine.ext.db. * Property«, например, если вы хотите хранить целые числа, атрибут должен иметь тип google.appengine.ext. db.IntegerProperty .

С помощью опроса мы сохраняем 1. вопросы, задаваемые в вопросе атрибута , поэтому это тип db.StringProperty 2. кто задал вопрос в create_by , так что это тип db.UserProperty () 3. когда вопрос задавался в made_on , так что это типа db.DateTimeProperty . Аргумент ключевого слова auto_now_add указывает ORM добавить время, когда объект создается впервые.

Методы:

def __str__(self):
return '%s' %self.question

def get_absolute_url(self):
return '/poll/%s/' % self.key()

используются для получения строкового представления и URL-адреса опроса .

В выборе :

class Choice(db.Model):
poll = db.ReferenceProperty(Poll)
choice = db.StringProperty()
votes = db.IntegerProperty(default = 0)

Одновременно мы наследуем от db.Model и определяем атрибуты.

Написание форм

Django отслеживает формы Html, представляя их как объекты Python типа django.newsforms.Form .

Нам нужны два типа формы,

  1. Создать опрос.
  2. Чтобы создать выбор.

Итак, давайте создадим новый файл bforms.py и напишем это:

from django import newforms as forms
import models
from google.appengine.ext.db import djangoforms

class PollForm(djangoforms.ModelForm):
class Meta:
model = models.Poll
exclude = ['created_by']

class ChoiceForm(forms.Form):
choice = forms.CharField(max_length = 100)

def __init__(self, poll=None, *args, **kwargs):
self.poll = poll
super(ChoiceForm, self).__init__(*args, **kwargs)

def save(self):
choice = models.Choice(poll = self.poll, choice = self.clean_data['choice'])
choice.put()

Давайте рассмотрим каждую форму по очереди:

class PollForm(djangoforms.ModelForm):
class Meta:
model = models.Poll
exclude = ['created_by']

` PollForm ` является формой для создания нового Опрос . ` Google . приложение . доб . дб . Джангоформ . ModelForm ` позволяет создавать форму Django, соответствующую сущности Appengine . В ` модель = модели . Опрос ` мы определить , что Entiity мы хотим создать эту форму для . ` исключить = [ «CREATED_BY» ] ` сказать Django не создавать никакого поля для CREATED_BY , как мы этого не хотим , чтобы пользователи , чтобы изменить это .

Для ChoiceForm:

class ChoiceForm(forms.Form):
choice = forms.CharField(max_length = 100)

def __init__(self, poll=None, *args, **kwargs):
self.poll = poll
super(ChoiceForm, self).__init__(*args, **kwargs)

def save(self):
choice = models.Choice(poll = self.poll, choice = self.clean_data['choice'])
choice.put()

Мы хотим, чтобы эта форма создала выбор для определенного опроса , поэтому мы расширяем формы. Формы и определяем поля, которые мы хотим в этой форме. выбор = forms.CharField (max_length = 100) говорит Джанго , что мы хотим , чтобы поле с Html текстового поля .

В def save (self): мы определяем действие, которое происходит, когда мы хотим сохранить данные, связанные с этим опросом. choice = models.Choice (poll = self.poll, choice = self.clean_data ['choice']) создает объект Choice, а choice.put () сохраняет объект в базе данных. .clean_data — это способ поиска данных, связанных с полем.

Мы не написали .save mthod для PollForm, так как у этой ModelForm уже есть метод .save для сохранения связанного объекта.

Написать мнение

У нас есть четыре типа страниц и четыре записи в urls.py. Поэтому нам нужно создать четыре функции, которые сопоставляются с четырьмя шаблонами URL. Отредактируйте файл views.py так, чтобы он выглядел следующим образом. Если вы не понимаете, не беспокойтесь, так как мы рассмотрим это:

from django.http import HttpResponse, HttpResponseRedirect
from pollango.poll import models
import bforms
from django.shortcuts import render_to_response

def render(template, payload):
payload['recents'] = models.Poll.all().order('-created_on').fetch(5)
return render_to_response(template, payload)

def index(request):
polls = models.Poll.all().order('-created_on').fetch(20)
payload = dict(polls = polls)
return render('index.html', payload)

def create(request):
if request.method == 'GET':
pollform = bforms.PollForm()
choiceforms = []
for i in range(4):
choiceforms.append(bforms.ChoiceForm(prefix = 'f%s'%i))
if request.method == 'POST':
pollform = bforms.PollForm(request.POST)
choiceform = bforms.ChoiceForm()
if pollform.is_valid():
poll = pollform.save()
choiceforms = []
for i in range(4):
choiceforms.append(bforms.ChoiceForm(poll=poll, prefix = 'f%s'%i, data=request.POST))
for form in choiceforms:
if form.is_valid():
form.save()
return HttpResponseRedirect(poll.get_absolute_url())
payload = dict(pollform=pollform, choiceforms=choiceforms)
return render('create.html', payload)

def poll_detail(request, poll_key):
poll = models.Poll.get(poll_key)
choices = models.Choice.all().filter('poll = ', poll)
if request.method == 'POST':
choice_key = request.POST['value']
choice = models.Choice.get(choice_key)
choice.votes += 1
choice.put()
return HttpResponseRedirect('./results/')
payload = dict(poll = poll, choices = choices)
return render('poll_details.html', payload)

def poll_results(request, poll_key):
poll = models.Poll.get(poll_key)
choices = models.Choice.all().filter('poll = ', poll)
payload = dict(poll = poll, choices = choices)
return render('poll_results.html', payload)

def index (запрос) — это первая функция, которая вызывается в respose к URL. Это было определено в строке (r '^ $', 'pollango.poll.views.index') .

def index(request):
polls = models.Poll.all().order('-created_on').fetch(20)
payload = dict(polls = polls)
return render('index.html', payload)

В опросах = models.Poll.all () порядка ( '- created_on').. Выборки (20) , models.Poll.all () получить нас все Poll объекты, .order ( '- CREATED_BY') заказывает QuerySet в порядке убывания от CREATED_BY и .fetch (20) ограничивает QuerySet до 20 объектов. Это то же самое, что написать SQL-запрос:

SELECT *
FROM poll
ORDER BY created_on DESC
LIMIT 0, 30

Наборы запросов лениво оцениваются, поэтому загружаются только те объекты, которые вы используете.

Чтобы преобразовать это в Html, мы вызываем render , передавая ему словарь объектов, которые необходимо отобразить. render в свою очередь вызывает render_to_response (template, payload), передавая ему словарь объектов и используемый шаблон. Мы увидим, как шаблоны работают через минуту.

Вторая функция просмотра — это создать :

def create(request):
if request.method == 'GET':
pollform = bforms.PollForm()
choiceforms = []
for i in range(4):
choiceforms.append(bforms.ChoiceForm(prefix = 'f%s'%i))
if request.method == 'POST':
pollform = bforms.PollForm(request.POST)
choiceform = bforms.ChoiceForm()
if pollform.is_valid():
poll = pollform.save()
choiceforms = []
for i in range(4):
choiceforms.append(bforms.ChoiceForm(poll=poll, prefix = 'f%s'%i, data=request.POST))
for form in choiceforms:
if form.is_valid():
form.save()
return HttpResponseRedirect(poll.get_absolute_url())
payload = dict(pollform=pollform, choiceforms=choiceforms)
return render('create.html', payload)

Это отвечает за показ формы для создания нового опроса и дескриптора при отправке форм. При получении HTTP-запроса get отображается форма. Когда есть HTTP пост-запрос, функция создает новый опрос:

if request.method == 'GET':
pollform = bforms.PollForm()
choiceforms = []
for i in range(4):
choiceforms.append(bforms.ChoiceForm(prefix = 'f%s'%i))

Это создает форму для создания объекта сущности Опрос и формы для создания связанного выбора . Эти формы были определены в bforms.py .

bforms.py

if request.method == 'POST':
pollform = bforms.PollForm(request.POST)
choiceform = bforms.ChoiceForm()
if pollform.is_valid():
poll = pollform.save()
choiceforms = []
for i in range(4):
choiceforms.append(bforms.ChoiceForm(poll=poll, prefix = 'f%s'%i, data=request.POST))
for form in choiceforms:
if form.is_valid():
form.save()
return HttpResponseRedirect(poll.get_absolute_url())

Когда будет выполнен запрос POST, request.method будет иметь значение POST. В этом случае мы проверяем, ввел ли пользователь значение, используя pollform.is_valid () и form.is_valid () . Если пользователь ввел значение, мы выполняем form.save () , которая вызывает obj.put и сохраняет объект в базе данных.

Как только у этой функции есть объекты, которые она хочет показать, она вызывает render, передавая объекты.

В poll_detail и poll_results мы хотим показать опрос и его ассоциированный выбор . Если ключ опроса — xxxyyyyzzzz, тогда poll_detail будет вызываться в ответ на URL / poll / xxxyyyyzzzz / . В этом случае poll_details будет вызываться с аргументами xxxyyyyzzzz как poll_key , поскольку первым аргументом является объект HttpRequest с данными о текущем запросе:

def poll_detail(request, poll_key):
poll = models.Poll.get(poll_key)
choices = models.Choice.all().filter('poll = ', poll)
if request.method == 'POST':
choice_key = request.POST['value']
choice = models.Choice.get(choice_key)
choice.votes += 1
choice.put()
return HttpResponseRedirect('./results/')
payload = dict(poll = poll, choices = choices)
return render('poll_details.html', payload)

В models.Poll.get (poll_key) мы получаем один объект с ключом poll_key . Это эквивалентно запросу SQL:

SELECT * FROM poll
WHERE key = poll_key

с выбором = models.Choice.all (). фильтр ( «опрос = », опрос) `` мы получаем все в `` Choice объекты , которые для этого опроса . Это эквивалентно:

SELECT *
FROM choice
WHERE poll_id = poll.id

Обратите внимание, что вы можете прямо сказать, что фильтр ('poll = ', poll) , ссылки и разыменование ключей происходит за кулисами.

Когда у нас есть объекты Poll и Choice , мы передаем их для рендеринга, который отображает страницу с этими объектами.

poll_results также очень похож, он получает те же объекты, но отображает другую страницу.

Написание шаблонов

Если у вас есть PHP или похожие языки, вы можете обнаружить, что шаблоны Django ограничены. Шаблоны предназначены для отображения логики представления, и поэтому вы можете писать не полный Python, а упрощенный язык шаблонов.

Без дальнейших церемоний вот шаблон для индексной страницы:

{% extends 'base.html' %}

{% block title %}
Pollengine - A polling app built with Django, and Appengine
{% endblock %}

{% block contents %}
<h2>Pollengine - A polling app built with Django, and Appengine </h2>

{% for poll in polls %}
<div class="poll">
<a href="{{poll.get_absolute_url}}">{{poll.question}}</a>
<br>
By {{poll.user}} on {{poll.created_on|date}}
</div>
{% endfor %}
{% endblock %}

Теги и объекты ____________________________________________

Вы увидите два типа конструкций. {% ... %} называются тегами, они позволяют вам использовать прогремонтные конструкции, такие как циклы. {{ .. }} позволяет получить доступ к объектам, которые вы передали в шаблон. Например, в индексе функции мы передали переменные опросы в шаблон, поэтому вы можете использовать {{polls}}, если хотите. Но вещи становятся немного более интересными с тегами.

Для большинства сайтов у вас есть общие элементы, такие как элементы навигации, и было бы расточительно указывать это на каждой странице. Django позволяет расширять шаблоны. Базовый шаблон определяет элементы, на которые должны переходить дочерние шаблоны. Давайте посмотрим на родительский шаблон index.html :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>
{% block title %}
Page title
{% endblock %}
</title>

<style type="text/css">
<!--
.contents{
width: 70%;
float: right;
}
.sidebar{
width: 25%;
float: right;
}
-->
</style>

</head>
<body>

<div class="contents">

{% block contents %}

asdf
{% endblock %}
</div>

<div class="sidebar">
{% block sidebar %}
<h3>Meta</h3>
<ul>
<li>
<a href="/create/"> Create new Poll</a>

</li>
</ul>

<h3>Recent Polls</h3>
<ul>
{% for poll in recents %}
<li>
<a href="{{poll.get_absolute_url}}">{{poll.question}}</a>

</li>
{% endfor %}
</ul>
{% endblock %}
</div>

</body>
</html>

Это простая HTML-страница. Но это обеспечивает три перехвата, где дочерние страницы могут переопределяться и вставляться специально для этих страниц. {% block contents %} указывает начало такой ловушки. Блоки закрываются с помощью {% endblock %} . Index.html переопределяет {% block contents %} , снова определяя этот блок. Заявление {% распространяется «base.html» %} сказал Джанго о родительском шаблоне index.html .

{% for poll in polls %} является циклической конструкцией, которая позволяла нам работать с каждым из опросов, переданных на эту страницу. Этот цикл закрыт {% endfor %} . Внутри этого цикла мы можем использовать {{poll}} для доступа к текущему объекту.

Есть три других шаблона, соответствующих каждой из других страниц. Поскольку они очень похожи, мы не будем вдаваться в детали,

create.html:

{% extends 'base.html' %}

{% block contents %}
<form action="." method="post">
{{pollform.as_p}}

{% for form in choiceforms %}
{{form.as_p}}
{% endfor %}

<input type="submit" name="createpoll" value="createpoll" />

</form>

{% endblock %}
poll_details.html:
{% extends 'base.html' %}

{% block title %}
{{poll.question}}
{% endblock %}

{% block contents %}
<div class="poll">
{{poll.question}}
<br />
{{poll.created_on|date}}
</div>

<br />
<form action="." method="post">
{% for choice in choices %}
<div class="choice">
{{ choice.choice }} <input type="radio" name="value" value="{{ choice.key }}">

</div>
{% endfor %}
<input type="submit" name="dovote" value="Choose" />
</form>
{% endblock %}

poll_results.html:

{% extends 'base.html' %}

{% block title %}
{{poll.question}} - results
{% endblock %}

{% block contents %}
<div class="poll">
{{poll.question}}
<br />
{{poll.created_on|date}}
</div>
<br />
{% for choice in choices %}

<div class="choice">
{{ choice.choice }}
{{choice.votes}}
</div>
{% endfor %}
{% endblock %}

Что дальше

Я надеюсь, что чтение этого урока вдохновит вас на потенциал Django. Вы можете узнать больше о Django на форуме Django и получить помощь, если вы застряли. Если у вас есть вопросы по поводу этого урока, оставьте комментарий в блоге 42topics.com , и я постараюсь вам помочь.

связи

Вы можете найти эти ссылки интересными.

  1. Джанго
  2. Джанго форум
  3. Appengine
  4. Живая установка
  5. Место загрузки