1. Panoramica
La serie di codelab Serverless Migration Station (esercitazioni pratiche e autonome) e i video correlati hanno lo scopo di aiutare gli sviluppatori serverless di Google Cloud a modernizzare le loro applicazioni guidandoli attraverso una o più migrazioni, principalmente abbandonando i servizi legacy. In questo modo, le tue app sono più portatili e hai più opzioni e flessibilità, il che ti consente di integrarti e accedere a una gamma più ampia di prodotti cloud e di eseguire più facilmente l'upgrade alle versioni più recenti del linguaggio. Sebbene inizialmente si concentri sui primi utenti di Cloud, principalmente gli sviluppatori di App Engine (ambiente standard), questa serie è abbastanza 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 del modulo 0. A questo punto, sarai pronto per migrare l'utilizzo a Cloud Storage nel modulo 16.
Imparerai a utilizzare
- Aggiungi l'utilizzo dell'API/libreria Blobstore di App Engine
- Memorizza i caricamenti degli utenti nel servizio
blobstore - Preparati al passaggio successivo per la migrazione a Cloud Storage
Che cosa ti serve
- Un progetto Google Cloud Platform con un account di fatturazione GCP attivo.
- Competenze di base di Python
- Conoscenza pratica dei comandi Linux più comuni
- Conoscenza di base dello sviluppo e del deployment di app App Engine
- Un'app App Engine del Modulo 0 funzionante (scaricala dal repository)
Sondaggio
Come utilizzerai questo tutorial?
Come valuteresti la tua esperienza con Python?
Come valuti la tua esperienza di utilizzo dei servizi Google Cloud?
2. Sfondo
Per eseguire la migrazione dall'API Blobstore di App Engine, aggiungi il relativo utilizzo all'app ndb di base di App Engine esistente del modulo 0. L'app di esempio mostra le dieci visite più recenti dell'utente. Stiamo modificando l'app per chiedere all'utente finale di caricare un artefatto (un file) corrispondente alla sua "visita". Se l'utente non vuole farlo, può selezionare l'opzione "Salta". Indipendentemente dalla decisione dell'utente, la pagina successiva restituisce 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. Una delle cose che rende diverso questo esempio (oltre all'aggiunta dell'accesso a Blobstore) è che passa dall'utilizzo di Django nel modulo 0 a Jinja2 nel modulo 15. Un passaggio fondamentale per modernizzare le app 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 questa direzione implementando Jinja2 rimanendo su webapp2 per l'accesso a Blobstore. Poiché Flask utilizza Jinja2 per impostazione predefinita, non sarà necessario apportare modifiche al modello nel modulo 16.
3. Configurazione/preparazione
Prima di passare alla parte principale del tutorial, configura il progetto, recupera il codice ed esegui il deployment dell'app di base per iniziare con il codice funzionante.
1. Configura il progetto
Se hai già eseguito il deployment dell'app Modulo 0, ti consigliamo di riutilizzare lo stesso progetto (e codice). In alternativa, puoi creare un nuovo progetto o riutilizzarne uno esistente. Assicurati che il progetto abbia un account di fatturazione attivo e che App Engine sia abilitato.
2. Ottieni l'app di esempio di base
Uno dei prerequisiti di questo codelab è avere un'app di esempio del modulo 0 funzionante. Se non ce l'hai, puoi scaricarla dalla cartella "START" del modulo 0 (link di seguito). Questo codelab ti guida in ogni passaggio e si conclude con un codice simile a quello presente nella cartella "FINISH" del modulo 15.
- INIZIO: Cartella del modulo 0 (Python 2)
- FINE: Cartella Modulo 15 (Python 2)
- Intero repository (per clonare o scaricare il file ZIP)
La directory dei file START di Module 0 dovrebbe avere il seguente aspetto:
$ ls README.md index.html app.yaml main.py
3. (Esegui di nuovo il deployment dell'app di base
I passaggi preliminari rimanenti da eseguire ora:
- Acquisisci di nuovo 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
Una volta eseguiti correttamente questi passaggi e verificato che la tua app web funzioni (con un output simile a quello riportato di seguito), puoi aggiungere l'utilizzo della memorizzazione nella cache alla tua app.

4. Aggiorna i file di configurazione
app.yaml
Non sono previste modifiche sostanziali alla configurazione dell'applicazione, tuttavia, come accennato in precedenza, stiamo passando dai modelli Django (predefiniti) a Jinja2, quindi per eseguire il passaggio, gli utenti devono specificare l'ultima versione di Jinja2 disponibile sui server App Engine 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 file app.yaml aggiungendo una nuova sezione libraries come mostrato qui:
DOPO:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
Non è necessario aggiornare altri file di configurazione, quindi passiamo ai file dell'applicazione.
5. Modificare i file dell'applicazione
Importazioni e supporto di Jinja2
Il primo insieme di modifiche per main.py include l'aggiunta dell'utilizzo dell'API Blobstore e la sostituzione dei modelli Django con Jinja2. Ecco cosa cambierà:
- Lo scopo del modulo
osè creare un percorso del file a un modello Django. Poiché stiamo passando a Jinja2, dove questa operazione viene gestita, l'utilizzo diose del renderer dei modelli Django,google.appengine.ext.webapp.template, non è più necessario, pertanto verranno rimossi. - Importa l'API Blobstore:
google.appengine.ext.blobstore - Importa i gestori Blobstore trovati nel framework
webapporiginale. 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
Implementa le modifiche nell'elenco riportato sopra 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'utilizzo di Jinja2 come definito nella documentazione di webapp2_extras. Il seguente snippet di codice esegue il wrapping della classe di gestione delle richieste webapp2 standard 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))
Aggiungere il supporto di Blobstore
A differenza di altre migrazioni di questa serie in cui manteniamo la funzionalità o l'output dell'app di esempio identici (o quasi) senza (molte) modifiche all'esperienza utente, questo esempio si discosta in modo più radicale dalla norma. Anziché registrare immediatamente una nuova visita e mostrare le dieci più recenti, stiamo aggiornando l'app per chiedere all'utente un artefatto di file per registrare la visita. Gli utenti finali possono quindi caricare un file corrispondente o selezionare "Salta" per non caricare nulla. Una volta completato questo passaggio, viene visualizzata la pagina "Visite più recenti".
Questa modifica consente alla nostra app di utilizzare il servizio Blobstore per archiviare (e possibilmente eseguire il rendering in un secondo momento) l'immagine o un altro tipo di file nella pagina delle visite più recenti.
Aggiornare il modello di dati e implementarne l'utilizzo
Stiamo memorizzando più dati, in particolare aggiornando il modello di dati per memorizzare l'ID (chiamato "BlobKey") del file caricato in Blobstore e aggiungendo un riferimento per salvarlo in store_visit(). Poiché questi dati aggiuntivi vengono restituiti insieme a tutto il resto al momento della query, fetch_visits() rimane invariato.
Ecco il prima e il dopo con 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 illustrata delle modifiche apportate finora:

Supportare i caricamenti di file
La modifica più significativa della funzionalità è il supporto dei caricamenti di file, che si tratti di chiedere all'utente un file, supportare la funzionalità "Salta" o eseguire il rendering di un file corrispondente a una visita. Tutto fa parte del quadro. Di seguito sono riportate le modifiche necessarie per supportare i caricamenti di file:
- La richiesta del gestore principale
GETnon recupera più le visite più recenti per la visualizzazione. Al contrario, chiede all'utente di caricare un file. - Quando un utente finale invia un file da caricare o salta questo processo, un
POSTdel modulo passa il controllo al nuovoUploadHandler, derivato dagoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler. - Il metodo
POSTdiUploadHandleresegue il caricamento, chiamastore_visit()per registrare la visita e attiva un reindirizzamento HTTP 307 per reindirizzare l'utente a "/", dove… - Il metodo
POSTdel gestore principale esegue 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 e seguita dallo stesso reindirizzamento. - Le visite più recenti includono un nuovo campo visualizzato dall'utente, ovvero un "visualizza" con collegamento ipertestuale se è disponibile un file di caricamento o "nessuno" in caso contrario. Queste modifiche vengono implementate nel modello HTML insieme all'aggiunta di un modulo di caricamento (maggiori informazioni a breve).
- Se un utente finale fa clic sul link "Visualizza" per una visita con un video caricato, viene inviata una richiesta
GETa un nuovoViewBlobHandler, derivato dagoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler, che esegue il rendering del file se è un'immagine (nel browser, se supportato), chiede di scaricarlo in caso contrario o restituisce un errore HTTP 404 se non viene trovato. - Oltre alla nuova coppia di classi di gestione e alla nuova coppia di route per inviare il traffico, il gestore principale ha bisogno di un nuovo metodo
POSTper ricevere il reindirizzamento 307 descritto sopra.
Prima di questi aggiornamenti, l'app Module 0 includeva solo un gestore principale con un metodo GET e un singolo percorso:
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 sono presenti tre gestori: 1) il gestore di caricamento con un metodo POST, 2) un gestore di download "visualizza blob" 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 ora appaia come di seguito.
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)
Nel codice appena aggiunto sono presenti diverse chiamate chiave:
- In
MainHandler.get, c'è una chiamata ablobstore.create_upload_url. Questa chiamata genera l'URL a cui viene inviato il moduloPOST, chiamando il gestore di caricamento per inviare il file a Blobstore. - In
UploadHandler.post, c'è una chiamata ablobstore_handlers.BlobstoreUploadHandler.get_uploads. È questa la vera magia che inserisce il file in Blobstore e restituisce un ID univoco e persistente per il file, il suoBlobKey. - In
ViewBlobHandler.get, la chiamata diblobstore_handlers.BlobstoreDownloadHandler.sendconBlobKeydi un file comporta il recupero del file e il suo inoltro al browser dell'utente finale
Queste chiamate rappresentano la maggior parte dell'accesso alle funzionalità aggiunte all'app. Ecco una rappresentazione illustrata di questo secondo e ultimo insieme di modifiche a main.py:

Aggiornare il modello HTML
Alcuni degli aggiornamenti all'applicazione principale influiscono sull'interfaccia utente (UI) dell'app, pertanto sono necessarie modifiche corrispondenti nel modello web, due per la precisione:
- È necessario un modulo di caricamento dei file con tre elementi di input: un file e una coppia di pulsanti di invio per il caricamento e l'omissione del file, rispettivamente.
- Aggiorna l'output delle visite più recenti aggiungendo un link "Visualizza" per le visite con un caricamento di file corrispondente o "nessuno" in caso contrario.
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>
Implementa le modifiche nell'elenco sopra per creare 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 a index.html:

Un'ultima modifica è che Jinja2 preferisce i modelli in una cartella templates, quindi crea questa cartella e sposta index.html al suo interno. Con questo passaggio finale, 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 di Blobstore sono visibili nella console Google Cloud, in particolare nel browser di Cloud Storage. La domanda è dove. La risposta è il bucket Cloud Storage predefinito dell'app App Engine. Il suo nome è il nome di dominio completo dell'app App Engine, PROJECT_ID.appspot.com. È molto comodo perché tutti gli ID progetto sono univoci, giusto?
Gli aggiornamenti apportati all'applicazione di esempio inseriscono i file caricati in questo bucket, ma gli sviluppatori hanno la possibilità di scegliere una posizione più specifica. Il bucket predefinito è accessibile a livello di programmazione tramite google.appengine.api.app_identity.get_default_gcs_bucket_name(), il che richiede una nuova importazione se vuoi accedere a questo valore, ad esempio per utilizzarlo come prefisso per organizzare i file caricati. Ad esempio, l'ordinamento per tipo di file:

Per implementare un'operazione simile per le immagini, ad esempio, avrai un codice come questo insieme a un codice che controlla 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')
Inoltre, convaliderai le immagini caricate utilizzando uno strumento come il modulo imghdr della libreria standard Python per confermare il tipo di immagine. Infine, probabilmente vorrai limitare le dimensioni dei caricamenti in caso di malintenzionati.
Supponiamo che tutto questo sia stato fatto. Come possiamo aggiornare la nostra app per supportare la specifica della posizione in cui 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 nel seguente modo:
blobstore.create_upload_url('/upload', gs_bucket_name=IMAGE_BUCKET))
Poiché si tratta di un aggiornamento facoltativo se vuoi specificare la destinazione dei caricamenti, non fa parte del file main.py nel repository. In alternativa, nel repository è disponibile un'alternativa denominata main-gcs.py per la tua revisione. Anziché utilizzare una "cartella" bucket separata, il codice in main-gcs.py archivia i caricamenti nel bucket "root" (PROJECT_ID.appspot.com) proprio come main.py, ma fornisce l'impalcatura necessaria per derivare l'esempio 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
Questa sezione conclude il codelab eseguendo il deployment dell'app, verificando che funzioni come previsto e in qualsiasi output riflesso. Dopo la convalida dell'app, esegui i passaggi di pulizia e valuta i passaggi successivi.
Esegui il deployment e verifica l'applicazione
Esegui di nuovo il deployment dell'app con gcloud app deploy e verifica che funzioni come pubblicizzato, differendo nell'esperienza utente (UX) dall'app del modulo 0. Ora nella tua app sono presenti due schermate diverse, la prima è la richiesta del modulo di caricamento dei file di visita:
Da qui, gli utenti finali caricano un file e fanno clic su "Invia" oppure fanno clic su "Salta" per non caricare nulla. In entrambi i casi, il risultato è la schermata della visita più recente, ora arricchita con i link "Visualizza" o "Nessuno" tra i timestamp della visita e le informazioni sul visitatore:

Congratulazioni per aver completato questo codelab aggiungendo l'utilizzo di App Engine Blobstore all'app di esempio del modulo 0. Il tuo codice ora dovrebbe corrispondere a quello della cartella FINISH (Modulo 15). Nella cartella è presente anche l'alternativa main-gcs.py.
Esegui la pulizia
Generale
Se hai finito per il momento, ti consigliamo di disattivare l'app App Engine per evitare addebiti. Tuttavia, se vuoi fare altri test o esperimenti, la piattaforma App Engine ha una quota senza costi e, finché non superi questo livello di utilizzo, non ti verranno addebitati costi. Questo vale per il calcolo, ma potrebbero essere addebitati anche costi per i servizi App Engine pertinenti, quindi consulta la pagina dei prezzi per ulteriori informazioni. Se questa migrazione coinvolge altri servizi cloud, questi vengono fatturati separatamente. In entrambi i casi, se applicabile, consulta la sezione "Specifiche per questo codelab" di seguito.
Per una divulgazione completa, il deployment su una piattaforma di calcolo serverless di Google Cloud come App Engine comporta costi di build e archiviazione minimi. Cloud Build ha una propria quota senza costi, così come Cloud Storage. L'archiviazione di questa immagine utilizza parte della quota. Tuttavia, potresti vivere in una regione che non dispone di un livello senza costi, quindi tieni sotto controllo l'utilizzo dello spazio di archiviazione per ridurre al minimo i potenziali costi. Le "cartelle" Cloud Storage specifiche che devi esaminare includono:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- I link di archiviazione riportati sopra dipendono dalla tua
PROJECT_IDe dalla tua *LOC*, ad esempio "us" se la tua app è ospitata negli Stati Uniti.
D'altra parte, se non intendi continuare con questa applicazione o con altri codelab di migrazione correlati e vuoi eliminare tutto completamente, chiudi il progetto.
Specifico per questo codelab
I servizi elencati di seguito sono univoci per questo codelab. Per saperne di più, consulta la documentazione di ogni prodotto:
- Il servizio Blobstore di App Engine rientra nei limiti e nelle quote dei dati archiviati, pertanto consulta anche la pagina dei prezzi per i servizi in bundle legacy.
- Il servizio App Engine Datastore è fornito da Cloud Datastore (Cloud Firestore in modalità Datastore), che dispone anche di un livello senza costi. Per ulteriori informazioni, consulta la pagina dei prezzi.
Passaggi successivi
La successiva migrazione logica da prendere in considerazione è trattata nel modulo 16, che mostra agli sviluppatori come eseguire la migrazione dal servizio Blobstore di App Engine all'utilizzo della libreria client Cloud Storage. I vantaggi dell'upgrade includono la possibilità di accedere a più funzionalità di Cloud Storage e di acquisire familiarità con una libreria client che funziona per le app al di fuori di App Engine, sia in Google Cloud, in altri cloud o anche on-premise. Se ritieni di non aver bisogno di tutte le funzionalità disponibili in Cloud Storage o ti preoccupa il suo impatto sui costi, puoi continuare a utilizzare App Engine Blobstore.
Oltre al modulo 16, sono disponibili molte 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 di migrazione include tutti gli esempi di codice, i link a tutti i codelab e i video disponibili e fornisce anche indicazioni sulle migrazioni da prendere in considerazione e sull'"ordine" di migrazione pertinente.
7. Risorse aggiuntive
Problemi/feedback relativi ai codelab
Se riscontri problemi con questo codelab, cerca prima il tuo problema prima di presentare una segnalazione. Link per cercare e creare nuovi problemi:
Risorse per la migrazione
I link alle cartelle del repository per il modulo 0 (START) e il modulo 15 (FINISH) sono disponibili nella tabella di seguito. Puoi accedervi anche dal repository per tutte le migrazioni dei codelab di App Engine, che puoi clonare o scaricare come file ZIP.
Codelab | Python 2 | Python 3 |
Modulo 0 | N/A | |
Modulo 15 (questo codelab) | N/A |
Risorse online
Di seguito sono riportate risorse online che potrebbero essere pertinenti per questo tutorial:
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 su Python 2 App Engine
- Informazioni su prezzi e quote di App Engine
- Lancio della piattaforma App Engine di seconda generazione (2018)
- Confronto tra piattaforme di prima e seconda generazione
- Supporto a lungo termine per i runtime legacy
- Repository di esempi di migrazione della documentazione
- Repository di esempi di migrazione forniti dalla community
Google Cloud
- Python su Google Cloud Platform
- Librerie client Python di Google Cloud
- Livello "Sempre senza costi" di Google Cloud
- Google Cloud SDK (strumento a riga di comando gcloud)
- Tutta la documentazione di Google Cloud
Python
- Sistemi di modelli Django e Jinja2
- Framework web
webapp2 - Documentazione
webapp2 - Link
webapp2_extras webapp2_extrasDocumentazione di Jinja2
Video
- Serverless Migration Station
- Serverless Expeditions
- 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.