Цель работы: познакомиться с сервисом Amazon DynamoDB.
Amazon DynamoDB — это полностью управляемая NoSQL (Not only SQL) система управления базами данных с моделью данных типа “ключ-значение”. Она оптимизирована для быстрого и масштабируемого хранения данных с низкой задержкой.
Особенности:
DynamoDB не использует SQL, а базируется на принципе “ключ-значение”.
Важные понятия:
AWS позволяет бесплатно хранить в DynamoDB до 25 Гб данных.
Аналоги AWS DynamoDB:
Для работы с DynamoDB из программного кода используется SDK. AWS поддерживает SDK для всех основных промышленных языков программирования (Python, Java, JavaScript, C# и т.д.).
SDK AWS для Python называется Boto3.
Для подключения с помощью SDK используется тот же ключ что и для интерфейса командной строки (CLI).
Войдите в веб-консоль AWS.
Создайте ключ доступа (или используйте уже существующий) (меню пользователя, Security credentials, Access Keys).
key, тип данных numberНа локальном компьютере создайте каталог для проекта.
Создайте и активируйте виртуальное окружение Python.
Установите пакеты boto3, kaggle, flask и python-dotenv.
kaggle datasets download --unzip "harshitshankhdhar/imdb-dataset-of-top-1000-movies-and-tv-shows"
Создайте конфигурационный файл .env и скрипт load_data.py с помощью прилагаемых листингов.
load_data.py и документацию Boto3 DynamoDB. Внесите изменения, чтобы скрипт:
put_item()Запустите скрипт, в сервисе DynamoDB откройте раздел Explore items и убедитесь что данные успешно загрузились.
Выберите произвольный элемент, откройте редактор элемента и убедитесь что при загрузке сохранилась структура данных.
Создайте файлы app.py и templates\index.html.
Изучите исходный код в скрипте app.py и документацию Boto3 DynamoDB. Внесите изменения, чтобы скрипт получил данных о фильмах с помощью метода scan().
Запустите приложение на Flask и проверьте его работу в браузере:
flask run
Доп.задание: реализуйте возможность получения списка фильмов фильтром по части его названия.
get_item()..env
ACCESS_KEY_ID = ""
ACCESS_SECRET = ""
AWS_REGION = ""
TABLE_NAME = ""
load_data.py:
"""Поэлементная загрузка данных в таблицу DynamoDB"""
from csv import DictReader
from os import getenv
from pprint import pprint
import boto3
from dotenv import load_dotenv
N = 100
def load_data():
filename = 'imdb_top_1000.csv'
with open(filename, encoding='utf-8') as f:
reader = DictReader(f, delimiter=',', quotechar='"')
rows = [row for row in reader]
# Диагностический вывод прочитанных данных
# pprint(rows[:3])
return rows
def prepare_numeric(value):
if value:
return {'N': value.replace(',', '')}
else:
return {'N': '0'}
def main():
load_dotenv()
dynamo = boto3.client(
'dynamodb',
aws_access_key_id=getenv('ACCESS_KEY_ID'),
aws_secret_access_key=getenv('ACCESS_SECRET'),
region_name=getenv("AWS_REGION"),
)
rows = load_data()
for key, row in enumerate(rows[:N]):
poster_link, _, _ = row['Poster_Link'].rsplit('.', maxsplit=2)
poster_link += '._V1_SX300.jpg'
new_item = {
'key': {'N': str(key)},
'Title': {'S': row['Series_Title']},
'Poster': {'S': poster_link},
'Year': {'N': row['Released_Year']},
'Certificate': {'S': row['Certificate']},
'Runtime': {'S': row['Runtime']},
'Genre': {'L': [{'S': x.strip()} for x in row['Genre'].split(',')]},
'Rating': {'N': row['IMDB_Rating']},
'Overview': {'S': row['Overview']},
'Director': {'S': row['Director']},
'Stars': {'L':[
{'S': row['Star1']},
{'S': row['Star2']},
{'S': row['Star3']},
{'S': row['Star4']},
]},
'Meta_score': prepare_numeric(row.get('Meta_score')),
'Votes': prepare_numeric(row.get('No_of_Votes')),
'Gross': prepare_numeric(row.get('Gross')),
}
# Используйте метод put_item() для загрузки нового элемента
print(f'\r{key:3d}/{N} rows loaded', end='')
if __name__ == '__main__':
main()
app.py:
"""Сайт для просмотра данных из таблицы DynamoDB"""
from os import getenv
import boto3
from dotenv import load_dotenv
from flask import Flask, render_template, request
load_dotenv()
dynamo = boto3.client(
'dynamodb',
aws_access_key_id=getenv('ACCESS_KEY_ID'),
aws_secret_access_key=getenv('ACCESS_SECRET'),
region_name=getenv("AWS_REGION"),
)
app = Flask(__name__)
@app.route('/')
def index_page():
substring = request.args.get('q', '')
movies = []
# Используйте методы scan() и query() для получения данных
return render_template('index.html',
movies=movies,
substring=substring)
templates\index.html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DynamoDB</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<h1>Добро пожаловать!</h1>
</div>
</div>
<div class="row">
<div class="col">
<form>
<div class="mb-3">
<label for="q" class="form-label">Фильтр</label>
<input type="text" name="q" id="q" class="form-control" value="{{ substring }}">
</div>
</form>
</div>
</div>
<div class="row row-cols-1 row-cols-md-4">
{% for item in movies %}
<div class="col">
<div class="card">
<img src="{{ item['Poster']['S'] }}" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{ item['Title']['S'] }}</h5>
<p class="card-text">
Добавьте сюда описание фильма
</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</body>
</html>