1. Panoramica
La serie di codelab Serverless Migration Station (tutorial pratici e self-service) e i video correlati mirano ad aiutare gli sviluppatori Google Cloud serverless a modernizzare le applicazioni guidandoli attraverso una o più migrazioni, principalmente abbandonando i servizi legacy. In questo modo le tue app saranno più portabili e avrai più opzioni e flessibilità, consentendoti di integrare e accedere a una gamma più ampia di prodotti Cloud e di eseguire più facilmente l'upgrade a release delle lingue più recenti. Pur concentrandosi inizialmente sui primi utenti di Cloud, principalmente sviluppatori di App Engine (ambiente standard), questa serie è sufficientemente ampia da includere altre piattaforme serverless come Cloud Functions e Cloud Run, o altrove, se applicabile.
Questo codelab del modulo 15 spiega come aggiungere l'utilizzo di App Engine blobstore
all'app di esempio dal modulo 0. Dopodiché sarai pronto per eseguire la migrazione di tale utilizzo a Cloud Storage nel modulo 16.
Imparerai a utilizzare
- Aggiungi utilizzo dell'API/libreria App Engine Blobstore
- Archivia i caricamenti degli utenti sul servizio
blobstore
- Preparati per il passaggio successivo della migrazione a Cloud Storage
Che cosa ti serve
- Un progetto piattaforma Google Cloud con un account di fatturazione Google Cloud attivo
- Competenze Python di base
- Conoscenza pratica dei comandi Linux più comuni
- Conoscenza di base dello sviluppo e del deployment delle app App Engine
- Un'app App Engine Modulo 0 funzionante (ottenibile da un repository)
Sondaggio
Come utilizzerai questo tutorial?
Come valuteresti la tua esperienza con Python?
Come giudichi la tua esperienza di utilizzo dei servizi Google Cloud?
2. Sfondo
Per eseguire la migrazione dall'API App Engine Blobstore, aggiungine l'utilizzo all'app App Engine ndb
di base esistente dal Modulo 0. L'app di esempio mostra le dieci visite più recenti all'utente. Stiamo modificando l'app per richiedere all'utente finale di caricare un elemento (un file) corrispondente alla sua "visita". Se l'utente non vuole farlo, viene visualizzato un avviso "salta" . Indipendentemente dalla decisione dell'utente, nella pagina successiva viene visualizzato lo stesso output dell'app del Modulo 0 (e di molti altri moduli di questa serie). Con questa integrazione di App Engine blobstore
implementata, possiamo eseguirne la migrazione a Cloud Storage nel prossimo codelab (Modulo 16).
App Engine fornisce l'accesso ai sistemi di modelli Django e Jinja2 e una cosa che rende questo esempio diverso (oltre ad aggiungere l'accesso a Blobstore) è che passa dall'utilizzo di Django nel Modulo 0 a Jinja2 qui nel Modulo 15. Un passaggio fondamentale nella modernizzazione delle app di App Engine è la migrazione dei framework web da webapp2
a Flask. Quest'ultimo utilizza Jinja2 come sistema di modelli predefinito, quindi iniziamo a muoverci in quella direzione implementando Jinja2 rimanendo su webapp2
per l'accesso al Blobstore. Poiché Flask utilizza Jinja2 per impostazione predefinita, nel modulo 16 non saranno necessarie modifiche al modello.
3. Configurazione/pre-lavoro
Prima di passare alla parte principale del tutorial, configura il progetto, recupera il codice ed esegui il deployment dell'app di base per iniziare a lavorare con il codice.
1. Configura il progetto
Se hai già eseguito il deployment dell'app Modulo 0, ti consigliamo di riutilizzare lo stesso progetto (e lo stesso codice). In alternativa, puoi creare un nuovo progetto o riutilizzare un altro progetto esistente. Assicurati che il progetto abbia un account di fatturazione attivo e che App Engine sia abilitato.
2. Ottieni app di esempio di riferimento
Uno dei prerequisiti di questo codelab è avere un'app di esempio del Modulo 0 funzionante. Se non lo hai, puoi recuperarlo dal modulo 0 "START" cartella (link sotto). Questo codelab ti guida in ogni passaggio e si conclude con un codice simile a quello presente nel modulo 15 "FINISH" .
- AVVIA: cartella Modulo 0 (Python 2)
- FINISH: cartella del modulo 15 (Python 2)
- Intero repository (per clonare o scaricare il file ZIP)
La directory dei file STARTing del modulo 0 dovrebbe essere simile alla seguente:
$ ls README.md index.html app.yaml main.py
3. (Ri)Esegui il deployment dell'app di riferimento
I passaggi preliminari rimanenti da eseguire ora:
- Acquisisci familiarità con lo strumento a riga di comando
gcloud
- Esegui di nuovo il deployment dell'app di esempio con
gcloud app deploy
- Verifica che l'app venga eseguita su App Engine senza problemi
Dopo aver eseguito correttamente questi passaggi e aver verificato che la tua applicazione web funziona (con output simile all'output riportato di seguito), puoi iniziare ad aggiungere l'utilizzo della memorizzazione nella cache alla tua app.
4. Aggiorna i file di configurazione
app.yaml
Non sono state apportate modifiche sostanziali alla configurazione dell'applicazione. Tuttavia, come accennato in precedenza, stiamo passando dal modello Django (predefinito) a Jinja2, quindi per effettuare il passaggio, gli utenti devono specificare l'ultima versione di Jinja2 disponibile sui server App Engine e puoi farlo aggiungendola alla sezione delle librerie di terze parti integrate di app.yaml
.
PRIMA:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
Modifica il tuo file app.yaml
aggiungendo una nuova sezione libraries
come quella mostrata qui:
DOPO:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
Nessun altro file di configurazione deve essere aggiornato, quindi passiamo ai file dell'applicazione.
5. Modifica i file delle applicazioni
Importazioni e supporto di Jinja2
Il primo insieme di modifiche per main.py
include l'aggiunta dell'utilizzo dell'API Blobstore e la sostituzione del modello Django con Jinja2. Ecco cosa cambierà:
- Lo scopo del modulo
os
è creare un percorso file per un modello Django. Dal momento che stiamo passando a Jinja2, dove viene gestito questo aspetto, l'uso dios
e del renderer del modello di Django,google.appengine.ext.webapp.template
, non sono più necessari, perciò verranno rimossi. - Importa l'API Blobstore:
google.appengine.ext.blobstore
- Importa i gestori dell'archivio BLOB presenti nel framework
webapp
originale, che non sono disponibili inwebapp2
:google.appengine.ext.webapp.blobstore_handlers
- Importa il supporto Jinja2 dal pacchetto
webapp2_extras
PRIMA:
import os
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template
Implementare le modifiche nell'elenco precedente sostituendo la sezione di importazione corrente in main.py
con lo snippet di codice riportato di seguito.
DOPO:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
Dopo le importazioni, aggiungi del codice boilerplate per supportare l'uso di Jinja2 come definito nei documenti di webapp2_extras
. Il seguente snippet di codice unisce la classe standard del gestore di richieste webapp2 con la funzionalità Jinja2, quindi aggiungi questo blocco di codice a main.py
subito dopo le importazioni:
class BaseHandler(webapp2.RequestHandler):
'Derived request handler mixing-in Jinja2 support'
@webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(app=self.app)
def render_response(self, _template, **context):
self.response.write(self.jinja2.render_template(_template, **context))
Aggiungi supporto Blobstore
A differenza di altre migrazioni di questa serie in cui manteniamo la funzionalità o l'output dell'app di esempio identica (o quasi uguale) senza (molte) modifiche all'esperienza utente, questo esempio si discosta più radicalmente dalla norma. Anziché registrare immediatamente una nuova visita e visualizzare le dieci più recenti, stiamo aggiornando l'app per chiedere all'utente un elemento del file per registrare la sua visita. Gli utenti finali possono quindi caricare un file corrispondente o selezionare "Salta" per non caricare nulla. Una volta completato questo passaggio, le "visite più recenti" .
Questa modifica consente alla nostra app di utilizzare il servizio Blobstore per archiviare (ed eventualmente eseguire il rendering in un secondo momento) dell'immagine o di un altro tipo di file nella pagina delle visite più recenti.
Aggiornare il modello dei dati e implementarne l'utilizzo
Stiamo archiviando più dati, in particolare aggiornando il modello dei dati per archiviare l'ID (denominato "BlobKey
") del file caricato in Blobstore e aggiungendo un riferimento per salvare il file in store_visit()
. Poiché questi dati aggiuntivi vengono restituiti insieme a tutti gli altri dati al momento della query, fetch_visits()
rimane invariato.
Ecco i prima e dopo questi aggiornamenti con file_blob
, un ndb.BlobKeyProperty
:
PRIMA:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
DOPO:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
file_blob = ndb.BlobKeyProperty()
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
Ecco una rappresentazione grafica delle modifiche apportate finora:
Supporta i caricamenti di file
Il cambiamento più significativo nella funzionalità è il supporto del caricamento di file, che si tratti di richiedere all'utente un file o di "ignorare" l'azione o eseguire il rendering di un file corrispondente a una visita. Tutto fa parte del quadro. Queste sono le modifiche necessarie per supportare i caricamenti di file:
- La richiesta
GET
del gestore principale non recupera più le visite più recenti per la visualizzazione. ma richiede all'utente di eseguire un caricamento. - Quando un utente finale invia un file da caricare o ignora questo processo, un
POST
del modulo passa il controllo al nuovoUploadHandler
, derivato dagoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler
. - Il metodo
POST
diUploadHandler
esegue il caricamento, chiamastore_visit()
per registrare la visita e attiva un reindirizzamento HTTP 307 per rimandare l'utente a "/", dove... - Il metodo
POST
del gestore principale esegue una query (tramitefetch_visits()
) e mostra le visite più recenti. Se l'utente seleziona "Salta", non viene caricato alcun file, ma la visita viene comunque registrata, seguita dallo stesso reindirizzamento. - La visualizzazione delle visite più recenti include un nuovo campo mostrato all'utente, la "vista" collegata tramite link ipertestuale. se un file di caricamento è disponibile o se è impostato su "nessuno" negli altri casi. Queste modifiche vengono apportate nel modello HTML con l'aggiunta di un modulo di caricamento (ulteriori informazioni saranno disponibili a breve).
- Se un utente finale fa clic sul pulsante "Visualizza" per ogni visita con un video caricato, viene effettuata una richiesta
GET
a un nuovoViewBlobHandler
, derivato dagoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler
, eseguendo il rendering del file se si tratta di un'immagine (nel browser se supportata), la richiesta di download in caso contrario o la restituzione di un errore HTTP 404 se non trovata. - Oltre alla nuova coppia di classi di gestori e a una nuova coppia di route a cui inviare il traffico, il gestore principale ha bisogno di un nuovo metodo
POST
per ricevere il reindirizzamento 307 descritto sopra.
Prima di questi aggiornamenti, l'app Modulo 0 presentava solo un gestore principale con un metodo GET
e una singola route:
PRIMA:
class MainHandler(webapp2.RequestHandler):
'main application (GET) handler'
def get(self):
store_visit(self.request.remote_addr, self.request.user_agent)
visits = fetch_visits(10)
tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(tmpl, {'visits': visits}))
app = webapp2.WSGIApplication([
('/', MainHandler),
], debug=True)
Con questi aggiornamenti implementati, ora ci sono tre gestori: 1) gestore del caricamento con un metodo POST
, 2) "visualizza blob" gestore dei download con un metodo GET
e 3) il gestore principale con i metodi GET
e POST
. Apporta queste modifiche in modo che il resto dell'app abbia ora l'aspetto seguente.
DOPO:
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
'Upload blob (POST) handler'
def post(self):
uploads = self.get_uploads()
blob_id = uploads[0].key() if uploads else None
store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
self.redirect('/', code=307)
class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
'view uploaded blob (GET) handler'
def get(self, blob_key):
self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)
class MainHandler(BaseHandler):
'main application (GET/POST) handler'
def get(self):
self.render_response('index.html',
upload_url=blobstore.create_upload_url('/upload'))
def post(self):
visits = fetch_visits(10)
self.render_response('index.html', visits=visits)
app = webapp2.WSGIApplication([
('/', MainHandler),
('/upload', UploadHandler),
('/view/([^/]+)?', ViewBlobHandler),
], debug=True)
Il codice che abbiamo appena aggiunto include diverse chiamate chiave:
- Tra
MainHandler.get
, c'è una chiamata al numeroblobstore.create_upload_url
. Questa chiamata genera l'URL del moduloPOST
, chiamando il gestore di caricamento per inviare il file a Blobstore. - Tra
UploadHandler.post
, c'è una chiamata al numeroblobstore_handlers.BlobstoreUploadHandler.get_uploads
. Questa è la vera magia che inserisce il file in Blobstore e restituisce un ID univoco e permanente per il file, il suoBlobKey
. - In
ViewBlobHandler.get
, la chiamata diblobstore_handlers.BlobstoreDownloadHandler.send
con il valoreBlobKey
di un file comporta il recupero del file e l'inoltro al browser dell'utente finale
Queste chiamate rappresentano la maggior parte dell'accesso alle funzionalità aggiunte all'app. Ecco una rappresentazione grafica di questa seconda e ultima serie di modifiche a main.py
:
Aggiorna modello HTML
Alcuni degli aggiornamenti dell'applicazione principale influiscono sull'interfaccia utente (UI), pertanto le corrispondenti modifiche sono necessarie nel modello web. Di fatto, due sono:
- È richiesto un modulo di caricamento file con tre elementi di input: un file e una coppia di pulsanti di invio rispettivamente per caricare e saltare i file.
- Aggiorna l'output delle visite più recenti aggiungendo una "vista" link per le visite con un caricamento file corrispondente o "nessuno" negli altri casi.
PRIMA:
<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>
<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>
</body>
</html>
Implementare le modifiche nell'elenco precedente per comprendere il modello aggiornato:
DOPO:
<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>
<h1>VisitMe example</h1>
{% if upload_url %}
<h3>Welcome... upload a file? (optional)</h3>
<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
<input type="file" name="file"><p></p>
<input type="submit"> <input type="submit" value="Skip">
</form>
{% else %}
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }}
<i><code>
{% if visit.file_blob %}
(<a href="/view/{{ visit.file_blob }}" target="_blank">view</a>)
{% else %}
(none)
{% endif %}
</code></i>
from {{ visit.visitor }}
</li>
{% endfor %}
</ul>
{% endif %}
</body>
</html>
Questa immagine illustra gli aggiornamenti richiesti per index.html
:
Un'ultima modifica è che Jinja2 preferisce i propri modelli in una cartella templates
, quindi crea questa cartella e sposta index.html
al suo interno. Con questo ultimo spostamento, hai completato tutte le modifiche necessarie per aggiungere l'utilizzo di Blobstore all'app di esempio del Modulo 0.
(Facoltativo) "miglioramento" di Cloud Storage
Lo spazio di archiviazione Blobstore si è evoluto in Cloud Storage. Ciò significa che i caricamenti dell'archivio BLOB sono visibili nella console Cloud, in particolare nel browser di Cloud Storage. La domanda è dove. La risposta è il bucket Cloud Storage predefinito dell'app App Engine. Il nome è il nome del nome di dominio completo della tua app App Engine, PROJECT_ID
.appspot.com
. È così pratico perché tutti gli ID progetto sono univoci, giusto?
Gli aggiornamenti apportati all'applicazione di esempio eliminano i file caricati nel bucket, ma gli sviluppatori hanno la possibilità di scegliere una posizione più specifica. Il bucket predefinito è accessibile in modo programmatico tramite google.appengine.api.app_identity.get_default_gcs_bucket_name()
, il che richiede una nuova importazione per accedere a questo valore, ad esempio per utilizzarlo come prefisso per organizzare i file caricati. Ad esempio, ordinando per tipo di file:
Ad esempio, per implementare qualcosa di simile per le immagini, avrete un codice simile a questo insieme ad alcuni codici che controllano i tipi di file per scegliere il nome del bucket desiderato:
ROOT_BUCKET = app_identity.get_default_gcs_bucket_name()
IMAGE_BUCKET = '%s/%s' % (ROOT_BUCKET, 'images')
Convaliderai anche le immagini caricate utilizzando uno strumento come il modulo imghdr
della libreria standard di Python per confermare il tipo di immagine. Infine, ti consigliamo di limitare le dimensioni dei caricamenti in caso di utenti malintenzionati.
Diciamo che abbiamo fatto tutto. Come possiamo aggiornare l'app in modo che supporti la specifica dove archiviare i file caricati? La chiave è modificare la chiamata a blobstore.create_upload_url
in MainHandler.get
per specificare la posizione desiderata in Cloud Storage per il caricamento aggiungendo il parametro gs_bucket_name
in questo modo:
blobstore.create_upload_url('/upload', gs_bucket_name=IMAGE_BUCKET))
Poiché si tratta di un aggiornamento facoltativo, se vuoi specificare dove devono essere inviati i caricamenti, non fa parte del file main.py
nel repository. Nel repository è disponibile un'alternativa denominata main-gcs.py
che puoi esaminare. Anziché utilizzare una "cartella" di bucket separata, Il codice in main-gcs.py
archivia i caricamenti nella directory "principale" (PROJECT_ID
.appspot.com
) come main.py
, ma fornisce lo scaffolding necessario se dovessi ricavare il campione in qualcosa di più, come suggerito in questa sezione. Di seguito è riportata un'illustrazione delle "differenze" tra main.py
e main-gcs.py
.
6. Riepilogo/Pulizia
In questa sezione si conclude questo codelab eseguendo il deployment dell'app e verificando che funzioni come previsto e in qualsiasi output riportato. Dopo la convalida dell'app, esegui tutti i passaggi di pulizia e considera i passaggi successivi.
Esegui il deployment e verifica l'applicazione
Esegui di nuovo il deployment dell'app con gcloud app deploy
e conferma che l'app funzioni come pubblicizzato, in modo che l'esperienza utente (UX) differisca da quella dell'app Modulo 0. Ora la tua app presenta due diverse schermate, la prima è la richiesta di caricamento del modulo di visita del file:
Da qui, gli utenti finali caricano un file e fanno clic su "Invia" oppure fai clic su "Salta" per non caricare nulla. In entrambi i casi, il risultato è la schermata della visita più recente, ora arricchita con "visualizzazione" link o "nessuno" tra timestamp della visita e informazioni del visitatore:
Complimenti per aver completato questo codelab quando hai aggiunto l'utilizzo del Blobstore di App Engine all'app di esempio del Modulo 0. Ora il codice dovrebbe corrispondere al contenuto della cartella FINISH (Modulo 15). In questa cartella è presente anche l'alternativa main-gcs.py
.
Esegui la pulizia
Generale
Se per il momento hai finito, ti consigliamo di disabilitare l'app App Engine per evitare di incorrere in fatturazione. Tuttavia, se desideri eseguire altri test o sperimentarli, la piattaforma App Engine ha una quota senza costi, pertanto, se non superi il livello di utilizzo, non ti verrà addebitato alcun costo. Questo riguarda il computing, ma potrebbero essere addebitati costi anche per i servizi App Engine pertinenti, quindi consulta la pagina dei prezzi per ulteriori informazioni. Se la migrazione coinvolge altri servizi Cloud, questi vengono fatturati separatamente. In entrambi i casi, se applicabile, consulta la sezione "Specifici di questo codelab" di seguito.
Per garantire la piena divulgazione, il deployment su una piattaforma di serverless computing di Google Cloud come App Engine comporta costi minori di build e archiviazione. Cloud Build e Cloud Storage hanno una quota senza costi specifica. Lo spazio di archiviazione dell'immagine esaurisce una parte della quota. Tuttavia, potresti risiedere in una regione che non ha un livello senza costi, quindi tieni presente l'utilizzo dello spazio di archiviazione per ridurre al minimo i costi potenziali. "cartelle" specifiche di Cloud Storage da esaminare includono:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
- I link allo spazio di archiviazione riportati sopra dipendono dalla tua
PROJECT_ID
e dalla tua *LOC
*azione, ad esempio "us
" se la tua app è ospitata negli Stati Uniti.
Se invece non intendi continuare con questa applicazione o con altri codelab di migrazione correlati e vuoi eliminare tutto completamente, chiudi il progetto.
Specifico di questo codelab
I servizi elencati di seguito sono esclusivi per questo codelab. Per ulteriori informazioni, fai riferimento alla documentazione di ciascun prodotto:
- Il servizio Blobstore di App Engine rientra in Quote e limiti per i dati archiviati, quindi consultali e consulta la pagina dei prezzi dei servizi in bundle legacy.
- Il servizio App Engine Datastore è fornito da Cloud Datastore (Cloud Firestore in modalità Datastore), che prevede anche un livello senza costi; consulta la pagina relativa ai prezzi per ulteriori informazioni.
Passaggi successivi
La prossima migrazione logica da considerare è trattata nel modulo 16, che mostra agli sviluppatori come eseguire la migrazione dal servizio Blobstore di App Engine all'utilizzo della libreria client di Cloud Storage. I vantaggi dell'upgrade includono la possibilità di accedere a più funzionalità di Cloud Storage, acquisire familiarità con una libreria client che funziona per le app al di fuori di App Engine, in Google Cloud, in altri cloud o anche on-premise. Se non ritieni di aver bisogno di tutte le funzionalità disponibili in Cloud Storage o ti preoccupano gli effetti sui costi, puoi continuare a utilizzare App Engine Blobstore.
Oltre il Modulo 16 ci sono tutta una serie di altre possibili migrazioni come Cloud NDB e Cloud Datastore, Cloud Tasks o Cloud Memorystore. Esistono anche migrazioni tra prodotti a Cloud Run e Cloud Functions. Il repository per la migrazione contiene tutti gli esempi di codice, ti rimanda a tutti i codelab e i video disponibili e fornisce anche indicazioni sulle migrazioni da prendere in considerazione e su eventuali "ordini" pertinenti. delle migrazioni.
7. Risorse aggiuntive
Problemi/feedback del codelab
Se riscontri problemi con questo codelab, cercali prima di procedere con l'invio. Link per eseguire ricerche e creare nuovi problemi:
Risorse di migrazione
I link alle cartelle repository per il modulo 0 (START) e il modulo 15 (FINISH) sono disponibili nella tabella seguente. Sono inoltre accessibili dal repository per tutte le migrazioni del codelab di App Engine che puoi clonare o scaricare un file ZIP.
Codelab | Python 2 | Python 3 |
Modulo 0 | N/A | |
Modulo 15 (questo codelab) | N/A |
Risorse online
Di seguito sono riportate alcune risorse online che potrebbero essere pertinenti per questa esercitazione:
App Engine
- Servizio Blobstore di App Engine
- Quote e limiti dei dati archiviati di App Engine
- Documentazione di App Engine
- Runtime Python 2 App Engine (ambiente standard)
- Utilizzo delle librerie integrate di App Engine in App Engine per Python 2
- Informazioni su prezzi e quote di App Engine
- Lancio della piattaforma App Engine di seconda generazione (2018)
- Confronto tra primo e piattaforme di seconda generazione
- Assistenza a lungo termine per i runtime legacy
- Repository di esempi di migrazione della documentazione
- Repository di esempio sulla migrazione dei contributi della community
Google Cloud
- Python su Google Cloud Platform
- Librerie client di Google Cloud per Python
- "Sempre senza costi" di Google Cloud livello
- Google Cloud SDK (strumento a riga di comando gcloud)
- Tutta la documentazione di Google Cloud
Python
- Sistemi di creazione di modelli di Django e Jinja2
- Framework web
webapp2
- Documentazione di
webapp2
webapp2_extras
linkwebapp2_extras
Documentazione di Jinja2
Video
- Stazione di migrazione serverless
- Esplorazioni serverless
- Iscriviti a Google Cloud Tech
- Iscriviti a Google Developers
Licenza
Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.