1. Panoramica
La serie di codelab Serverless Migration Station (tutorial pratici autogestiti) e i video correlati mirano ad aiutare gli sviluppatori di Google Cloud serverless a modernizzare le loro applicazioni guidandoli attraverso una o più migrazioni, principalmente l'abbandono dei servizi legacy. In questo modo, le tue app sono più portabili e hai più opzioni e flessibilità, il che ti consente di integrarle e accedere a una gamma più ampia di prodotti Cloud ed eseguire più facilmente l'upgrade alle versioni più recenti dei linguaggi. 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 altre, se applicabile.
Questo codelab del Modulo 15 spiega come aggiungere l'utilizzo di blobstore di App Engine all'app di esempio del Modulo 0. Successivamente, nel Modulo 16, potrai eseguire la migrazione di questo utilizzo a Cloud Storage.
Imparerai a utilizzare
- Aggiungi l'utilizzo dell'API/libreria Blobstore di App Engine
- Archivia i caricamenti degli utenti nel servizio
blobstore - Preparati al passaggio successivo per eseguire la migrazione a Cloud Storage
Che cosa ti serve
- Un progetto Google Cloud con un account di fatturazione Google Cloud 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 valuteresti la tua esperienza con l'utilizzo dei servizi Google Cloud?
2. Sfondo
Per eseguire la migrazione dall'API Blobstore di App Engine, aggiungi il suo utilizzo all'app App Engine ndb di riferimento esistente del Modulo 0. L'app di esempio mostra all'utente le dieci visite più recenti. Stiamo modificando l'app in modo che chieda all'utente finale di caricare un artefatto (un file) corrispondente alla sua "visita". Se l'utente non vuole farlo, è disponibile un'opzione "Salta". Indipendentemente dalla decisione dell'utente, la pagina successiva mostra lo stesso output dell'app del Modulo 0 (e di molti altri moduli di questa serie). Una volta implementata questa integrazione di App Engine blobstore, 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 cosa che rende questo esempio diverso (oltre all'aggiunta dell'accesso all'archivio BLOB) è che passa dall'utilizzo di Django nel Modulo 0 a Jinja2 qui nel Modulo 15. Un passaggio chiave nella modernizzazione delle 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 e 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, ottieni 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 del 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. Scarica 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 attraverso ogni passaggio, per concludere con un codice simile a quello presente nella cartella "FINISH" del Modulo 15.
- START: cartella Modulo 0 (Python 2)
- FINE: cartella del modulo 15 (Python 2)
- Intero repository (per clonare o scaricare il file ZIP)
La directory dei file di INIZIO del Modulo 0 dovrebbe avere il seguente aspetto:
$ ls README.md index.html app.yaml main.py
3. (Riesegui il) deployment dell'app di base
I passaggi rimanenti della preparazione da eseguire ora:
- Acquisisci nuovamente 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 l'app web funziona (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 cambiare, 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 di seguito:
AFTER:
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. Modifica i file dell'applicazione
Supporto di importazioni e 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 nome file per un template Django. Poiché stiamo passando a Jinja2, dove questo viene gestito, l'utilizzo diose del renderer dei modelli Django,google.appengine.ext.webapp.template, non è più necessario, quindi vengono rimossi. - Importa l'API Blobstore:
google.appengine.ext.blobstore - Importa i gestori di Blobstore presenti nel framework
webapporiginale, che non sono disponibili inwebapp2:google.appengine.ext.webapp.blobstore_handlers - Importa il supporto di 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 l'attuale sezione di importazione in main.py con lo snippet di codice riportato di seguito.
AFTER:
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 un po' di codice boilerplate per supportare l'utilizzo di Jinja2 come definito nella documentazione di webapp2_extras. Il seguente snippet di codice racchiude la classe del gestore 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))
Aggiungi 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 alla UX, questo esempio si discosta in modo più radicale dalla norma. Anziché registrare immediatamente una nuova visita e poi visualizzare le dieci più recenti, stiamo aggiornando l'app per chiedere all'utente un file artefatto con cui 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 (ed eventualmente eseguire il rendering in un secondo momento) l'immagine o un altro tipo di file nella pagina delle visite più recenti.
Aggiorna il modello di dati e implementane l'utilizzo
Stiamo archiviando più dati, in particolare aggiornando il modello di dati per archiviare 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 che includono 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)
AFTER:
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:

Supporto dei caricamenti di file
La modifica più significativa alla funzionalità è il supporto dei caricamenti di file, sia che si tratti di chiedere all'utente un file, di supportare la funzionalità "Salta" o di eseguire il rendering di un file corrispondente a una visita. Tutto questo fa parte del quadro. Ecco le modifiche necessarie per supportare i caricamenti di file:
- La richiesta del gestore principale
GETnon recupera più le visite più recenti da visualizzare. ma chiede all'utente di caricarne uno. - Quando un utente finale invia un file da caricare o salta questa procedura, 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 rimandare l'utente a "/", dove… - Il metodo
POSTdel gestore principale esegue query (tramitefetch_visits()) e visualizza 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, ovvero un link ipertestuale "Visualizza" 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 (disponibile a breve).
- Se un utente finale fa clic sul link "Visualizza" per una visita con un video caricato, viene effettuata una richiesta
GETa un nuovoViewBlobHandler, derivato dagoogle.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler, che esegue il rendering del file se si tratta di un'immagine (nel browser, se supportato), richiede il download in caso contrario o restituisce un errore HTTP 404 se non viene trovato. - Oltre alla nuova coppia di classi di gestori 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 del Modulo 0 presentava 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 l'implementazione di questi aggiornamenti, ora sono presenti tre gestori: 1) 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 abbia l'aspetto seguente.
AFTER:
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 il moduloPOST, chiamando il gestore del 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 quel file, ovvero la suaBlobKey. - In
ViewBlobHandler.get, la chiamata diblobstore_handlers.BlobstoreDownloadHandler.sendcon l'BlobKeydi 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 questo secondo e ultimo insieme di modifiche a main.py:

Aggiorna il modello HTML
Alcuni degli aggiornamenti dell'applicazione principale influiscono sull'interfaccia utente (UI) dell'app, pertanto sono necessarie modifiche corrispondenti nel modello web, in particolare due:
- È necessario un modulo di caricamento file con tre elementi di input: un file e una coppia di pulsanti di invio, rispettivamente per il caricamento e il salto del file.
- Aggiorna l'output delle visite più recenti aggiungendo un link "visualizza" per le visite con un caricamento 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 riportato sopra per includere il modello aggiornato:
AFTER:
<!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 suoi 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 è poi evoluto in Cloud Storage. Ciò significa che i caricamenti di Blobstore sono visibili nella console Cloud, in particolare nel browser Cloud Storage. La domanda è: dove? La risposta è il bucket Cloud Storage predefinito della tua app App Engine. Il nome corrisponde al nome di dominio completo della tua 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 quel bucket, ma gli sviluppatori hanno la possibilità di scegliere una località più specifica. Il bucket predefinito è accessibile in modo programmatico tramite google.appengine.api.app_identity.get_default_gcs_bucket_name(), richiedendo 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 simile a 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 di 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 in questo modo:
blobstore.create_upload_url('/upload', gs_bucket_name=IMAGE_BUCKET))
Poiché si tratta di un aggiornamento facoltativo per specificare dove devono essere caricati i file, 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 se dovessi 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 questo codelab con il deployment dell'app, la verifica del suo funzionamento come previsto e l'analisi dell'output generato. Dopo la convalida dell'app, esegui i passaggi di pulizia e valuta i passaggi successivi.
Esegui il deployment e verifica l'applicazione
Esegui nuovamente il deployment dell'app con gcloud app deploy e verifica che funzioni come previsto, con un'esperienza utente (UX) diversa da quella dell'app del Modulo 0. Ora nell'app sono presenti due schermate diverse, la prima è il prompt del modulo di caricamento dei file di visita:
Da qui, gli utenti finali caricano un file e fanno clic su "Invia" o 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:

Complimenti per aver completato questo codelab aggiungendo l'utilizzo dell'archivio BLOB di App Engine all'app di esempio del Modulo 0. Il tuo codice dovrebbe ora corrispondere a quello nella cartella FINISH (Modulo 15). Anche l'alternativa main-gcs.py è presente in quella cartella.
Esegui la pulizia
Generale
Se hai finito, ti consigliamo di disattivare l'app App Engine per evitare addebiti. Tuttavia, se vuoi eseguire altri test o esperimenti, la piattaforma App Engine ha una quota senza costi, quindi, se non superi questo livello di utilizzo, non ti verranno addebitati costi. Questo vale per il computing, ma potrebbero essere addebitati anche i 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 "Specifico per questo codelab" di seguito.
Per completezza, il deployment su una piattaforma di serverless computing di Google Cloud come App Engine comporta costi minimi di build e archiviazione. Cloud Build ha una propria quota senza costi, così come Cloud Storage. L'archiviazione di questa immagine utilizza parte di questa quota. Tuttavia, potresti vivere in una regione che non dispone di un livello senza costi, quindi tieni d'occhio l'utilizzo dello spazio di archiviazione per ridurre al minimo i potenziali costi. Le "cartelle" di 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 allo spazio di archiviazione riportati sopra dipendono dal tuo
PROJECT_IDe 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, 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 ciascun prodotto:
- Il servizio Blobstore di App Engine rientra nelle quote e nei limiti dei dati archiviati, quindi 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 offre anche un livello senza costi. Per ulteriori informazioni, consulta la pagina dei prezzi.
Passaggi successivi
La migrazione logica successiva 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 e di acquisire familiarità con una libreria client che funziona per le app esterne ad 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 se temi che possa influire sui costi, puoi continuare a utilizzare l'archivio BLOB di App Engine.
Oltre al Modulo 16, sono possibili molte altre migrazioni, ad esempio Cloud NDB e Cloud Datastore, Cloud Tasks o Cloud Memorystore. Sono disponibili anche migrazioni tra prodotti a Cloud Run e Cloud Functions. Il repository di migrazione contiene tutti gli esempi di codice, i link a tutti i codelab e i video disponibili, oltre a fornire indicazioni sulle migrazioni da considerare e sull'"ordine" di migrazione pertinente.
7. Risorse aggiuntive
Problemi/feedback relativi ai codelab
Se riscontri problemi con questo codelab, cerca il problema prima di segnalarlo. 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 seguente. 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 le 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 di 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
- Assistenza 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 "Always Free" 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 di
webapp2 webapp2_extraslink- Documentazione di Jinja2
webapp2_extras
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.