Flask на примере –Интегрирование Flask и Angular

С настройкой очереди задач Redis давайте используем AngularJS для опроса серверной части, чтобы узнать, завершена ли задача, а затем обновим DOM, как только данные станут доступными.

Оглавление
•Текущая функциональность
•Обновите index.html
•Создайте модуль Angular
•Внедрение зависимостей и $ scope
•Рефакторинг app.py
•Базовый опрос
• Обновление DOM
•Заключение и следующие шаги

Обновления:
29.02.2010: Обновлен до версии Python 3.8.1.
22.03.2016: Обновлен до Python версии 3.5.1 и Angular версии 1.4.9.
02/22/2015: Добавлена поддержка Python 3.

Помните: вот что мы создаем - приложение Flask, которое вычисляет пары частот слов на основе текста из заданного URL-адреса.

Часть первая: Настройте локальную среду разработки, а затем разверните как промежуточную, так и производственную среду на Heroku.
Часть вторая: Настройте базу данных PostgreSQL вместе с SQLAlchemy и перегонным кубом для обработки миграций.
Часть третья: Добавьте внутреннюю логику для очистки, а затем обработайте количество слов с веб-страницы с помощью библиотек requests, BeautifulSoup и Natural Language Toolkit (NLTK).
Часть четвертая: Реализация очереди задач Redis для обработки текста.
Часть пятая: Настройте Angular на интерфейсе, чтобы постоянно опрашивать серверную часть, чтобы узнать, обработан ли запрос. (текущий)
Часть шестая: Переход на промежуточный сервер на Heroku - настройка Redis и подробное описание запуска двух процессов (веб-и рабочего) на одном динамо.
Часть седьмая: Обновите интерфейс, чтобы сделать его более удобным для пользователя.
Часть восьмая: Создайте пользовательскую угловую директиву для отображения диаграммы распределения частот с помощью JavaScript и D3.

Текущая функциональность

Во-первых, запустите Redis в одном окне терминала:

$ redis-server

В другом окне перейдите в каталог проекта и запустите рабочий:

$ cd flask-by-example
$ python worker.py
20:38:04 RQ worker started, version 0.5.6
20:38:04
20:38:04 *** Listening on default...

Наконец, откройте третье окно терминала, перейдите в каталог проекта и запустите основное приложение:

$ cd flask-by-example
$ python manage.py runserver

Открыть http://localhost:5000/ и проверьте с помощью URL-адреса https://realpython.com. В терминале должен быть выведен идентификатор задания. Возьмите идентификатор и перейдите по этому URL-адресу:

http://localhost:5000/results/add_the_job_id_here

Вы должны увидеть аналогичный ответ JSON в своем браузере:

[
  [
    "Python", 
    315
  ], 
  [
    "intermediate", 
    167
  ], 
  [
    "python", 
    161
  ], 
  [
    "basics", 
    118
  ], 
  [
    "web-dev", 
    108
  ], 
  [
    "data-science", 
    51
  ], 
  [
    "best-practices", 
    49
  ], 
  [
    "advanced", 
    45
  ], 
  [
    "django", 
    43
  ], 
  [
    "flask", 
    41
  ]
]

Теперь мы готовы добавить угловой.

Обновление index.html

Добавить угловой в index.html:

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>

Добавьте следующие директивы в index.html:

1. ng-app:
2. ng-controller:
3. ng-submit:

Итак, мы загрузили Angular, который говорит Angular рассматривать этот HTML - документ как приложение Angular, добавили контроллер, а затем добавили функцию GetResults (), которая запускается при отправке формы.

Создайте угловой модуль

Создайте “статический” каталог, а затем добавьте файл с именем main.js в этот каталог. Обязательно добавьте требование к index.html файл:

<script src="{{ url_for('static', filename='main.js') }}"></script>

Давайте начнем с этого базового кода:

(function () {
  'use strict';

  angular.module('WordcountApp', [])

  .controller('WordcountController', ['$scope', '$log',
    function($scope, $log) {
      $scope.getResults = function() {
        $log.log("test");
      };
    }
  ]);

}());

Здесь мы прикрепили результаты к объекту $scope, чтобы он был доступен в представлении.

Внедрение зависимостей и $ scope

В приведенном выше примере мы использовали внедрение зависимостей, чтобы «внедрить» объект $ scope и службу $ log. Остановите здесь. Очень важно понимать $ scope. Начните с документации по Angular, а затем обязательно прочтите вводное руководство по Angular, если вы еще этого не сделали.

.controller('WordcountController', ['$scope', '$log', '$http',
  function($scope, $log, $http) {

  $scope.getResults = function() {

    $log.log("test");

    // get the URL from the input
    var userInput = $scope.url;

    // fire the API request
    $http.post('/start', {"url": userInput}).
      success(function(results) {
        $log.log(results);
      }).
      error(function(error) {
        $log.log(error);
      });

  };

}
]);

Также обновите элемент ввода в index.html:

Мы внедрили службу $ http, взяли URL-адрес из поля ввода (через ng-model = "url"), а затем отправили запрос POST в серверную часть. Обратные вызовы успеха и ошибки обрабатывают ответ. В случае ответа 200 он будет обработан обработчиком успеха, который, в свою очередь, записывает ответ в консоль.

Перед тестированием давайте проведем рефакторинг серверной части, поскольку конечная точка / start в настоящее время не существует.

Рефакторинг app.py

Выполните рефакторинг создания задания Redis из функции просмотра индекса, а затем добавьте его в новую функцию просмотра с именем

get_counts ():
@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')
@app.route('/start', methods=['POST'])
def get_counts():
    # this import solves a rq bug which currently exists
    from app import count_and_save_words

    # get url
    data = json.loads(request.data.decode())
    url = data["url"]
    if not url[:8].startswith(('https://', 'http://')):
        url = 'http://' + url
    # start job
    job = q.enqueue_call(
        func=count_and_save_words, args=(url,), result_ttl=5000
    )
    # return created job id
    return job.get_id()

Не забудьте также добавить следующий импорт вверху:

импортировать json
Эти изменения должны быть простыми.

Теперь тестируем. Обновите браузер, отправьте новый URL. Вы должны увидеть идентификатор задания в консоли JavaScript. Идеально. Теперь, когда у Angular есть идентификатор задания, мы можем добавить функцию опроса.

Базовый опрос
Обновите main.js, добавив в контроллер следующий код:

function getWordCount(jobID) {
  var timeout = "";

  var poller = function() {
    // fire another request
    $http.get('/results/'+jobID).
      success(function(data, status, headers, config) {
        if(status === 202) {
          $log.log(data, status);
        } else if (status === 200){
          $log.log(data);
          $timeout.cancel(timeout);
          return false;
        }
        // continue to call the poller() function every 2 seconds
        // until the timeout is cancelled
        timeout = $timeout(poller, 2000);
      });
  };
  poller();
}

Затем обновите обработчик успеха в запросе POST:

$http.post('/start', {"url": userInput}).
  success(function(results) {
    $log.log(results);
    getWordCount(results);

  }).
  error(function(error) {
    $log.log(error);
  });

Не забудьте также добавить в контроллер службу $ timeout.
Что тут происходит?
1.Успешный HTTP-запрос приводит к срабатыванию функции getWordCount ().
2.В функции poller () мы вызвали конечную точку / results / job_id.
3.Используя службу $ timeout, эта функция продолжает срабатывать каждые 2 секунды до тех пор, пока тайм-аут не будет отменен, когда будет возвращен ответ 200 вместе с подсчетом слов. Ознакомьтесь с документацией по Angular, чтобы узнать, как работает служба $ timeout.
При тестировании обязательно откройте консоль JavaScript. Вы должны увидеть что-то похожее на это:

Nay! 202
Nay! 202
Nay! 202
Nay! 202
Nay! 202
Nay! 202
(10) [Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2)]

Итак, в приведенном выше примере функция poller () вызывается семь раз. Первые шесть вызовов вернули 202, а последний вызов вернул 200 вместе с массивом подсчета слов.

Идеально.

Теперь нам нужно добавить количество слов в DOM.

Updating the DOM

Update index.html:

Wordcount 3000


Frequencies


{% raw %}
{{wordcounts}}
{% endraw %}

Что мы изменили?

1.Тег input теперь имеет обязательный атрибут, указывающий на то, что поле ввода должно быть заполнено перед отправкой формы.
2.Попрощайтесь с тегами шаблона Jinja2. Jinja2 обслуживается на стороне сервера, и поскольку опрос полностью обрабатывается на стороне клиента, нам нужно использовать теги Angular. Тем не менее, поскольку теги шаблонов Jinja2 и Angular используют двойные фигурные скобки, {{}}, мы должны экранировать теги Jinja2, используя {% raw%} и {% endraw%}. Если вам нужно использовать несколько тегов Angular, рекомендуется изменить теги шаблонов, которые использует AngularJS, с помощью $ interpolateProvider. Для получения дополнительной информации ознакомьтесь с документацией по Angular.
Во-вторых, обновите обработчик успеха в функции poller ():

success(function(data, status, headers, config) {
  if(status === 202) {
    $log.log(data, status);
  } else if (status === 200){
    $log.log(data);
    $scope.wordcounts = data;
    $timeout.cancel(timeout);
    return false;
  }
  // continue to call the poller() function every 2 seconds
  // until the timeout is cancelled
  timeout = $timeout(poller, 2000);
});

Здесь мы прикрепили результаты к объекту $ scope, чтобы он был доступен в представлении.

Проверьте это. Если все прошло хорошо, вы должны увидеть объект на DOM. Не очень красиво, но это легко исправить с помощью Bootstrap, добавьте следующий код под div с id=results и удалите теги {% raw %} и {% endraw%}, которые обертывали div результатов из приведенного выше кода:

<div id="results">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Word</th>
        <th>Count</th>
      </tr>
    </thead>
    <tbody>
      {% raw %}
      <tr ng-repeat="element in wordcounts">

        <td>{{ element[0] }}</td>
        <td>{{ element[1] }}</td>

      </tr>
    {% endraw %}
    </tbody>
  </table>
</div>

 

Заключение и следующие шаги


Прежде чем перейти к построению графиков с помощью D3, нам все еще нужно:

1.Добавьте загрузочный счетчик: также известный как пульсатор, он будет отображаться до тех пор, пока задача не будет выполнена, чтобы конечный пользователь знал, что что-то происходит.
2.Рефакторинг углового контроллера: прямо сейчас в контроллере происходит слишком много (логики). Нам нужно перенести большую часть функциональности в сервис. Мы обсудим и почему, и как.
3.Обновление промежуточной среды: Нам нужно обновить промежуточную среду на Heroku - добавив изменения кода, нашего работника и Redis.

Увидимся в следующий раз!

Оригинал статьи

Flask на примере –Интегрирование Flask и Angular: 1 комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *