Для получения курсов воспользовался открытым API от ЦБ РФ, который возвращает XML файл с курсами валют на заданный день следующего вида:
<?xml version="1.0" encoding="windows-1251"?>
<ValCurs Date="21.04.2023" name="Foreign Currency Market">
<Valute ID="R01235">
<NumCode>840</NumCode>
<CharCode>USD</CharCode>
<Nominal>1</Nominal>
<Name>Доллар США</Name>
<Value>81,6188</Value>
</Valute>
<Valute ID="R01239">
<NumCode>978</NumCode>
<CharCode>EUR</CharCode>
<Nominal>1</Nominal>
<Name>Евро</Name>
<Value>89,4638</Value>
</Valute>
...
</ValCurs>
Если бы мне было нужно сделать задание максимально просто, то работа на этом бы и закончилась, т.к. API позволяет сразу запросить данные на нужную дату, однако смысл был в проверке, как я сделаю это, не имея этого функционала.
Так что, приложение при запросе нужной даты сначала проверяет, нет ли таковой в БД. Если есть - возвращает данные из БД, если нет, то запрашивает через API, возвращает их и записывает в БД.
Константы и создание логгера вынес в отдельный файл.
Тестов написать не успел, просто закинул пару простых для демонстрации, они в отдельном файле для тестов: tests.py
Flask
(Jijna
и бесплатныйBootstrap
шаблон) - для отображения страницы и основы.Django
уж слишком монструозен для такой задачиAPScheduler
- для создания повторяющейся задачи по проверке курса. Таска здесь нужна была одна, если бы была более сложная задача, использовал бы связкуCelery
+Redis
.datetime
для работы с датойrequests
для запросов к API ЦБ РФsqlite3
- для работы в БД sqLite. Т.к. не было задачи записывать много данных и обеспечивать гибкую работу с ними (+ обеспечивать совместимость с разными БД), то написал простой инструмент для работы с sqLite. Для более сложных задач использовал бы ORM и другую БД.xml
- для обработки xml от ЦБ РФlogging
- для логгеров, просто для демонстрацииtyping
- для тайпхинтовunittest
- для тестов
main.py:
@app.route("/")
def root():
"""Отображает основную страницу с текущим курсом валют"""
values = get_value([EUR, USD])
date = values.pop('date')
return render_template('index.html', date=date, values=values)
@app.route('/submit-date/', methods=['POST'])
def submit_date():
"""Забирает данные от формы ввода даты через Flask.request и возвращает результат с курсами на эту дату"""
date = request.form.get('date') # Получаем значение поля 'date' из формы. Данные придут в формате ГГГГ-ММ-ДД
if date:
date = '/'.join(date.split('-')[::-1])
values = get_value([EUR, USD], date)
date = values.pop('date')
return render_template('index.html', date=date, values=values)