Рубрики
Без рубрики

Серия Flask Series Часть 12: Индексирование пользователя введенных рецептов на основной странице поиска

Введение В предыдущем посте мы увидели, как позволить пользователям добавлять свои собственные рецепты в наше приложение … Tagged с Python, WebDev, Flask.

Серия колбы (13 части серии)

Введение

В предыдущем посте мы увидели, как позволить пользователям добавлять свои собственные рецепты в наше приложение. Работа, которую мы проделали, была в основном связана с базой данных: мы создали отношения между некоторыми из наших сущностей базы данных: Пользователь и User -createDrecipe И, используя эти отношения, нам удалось позволить пользователю добавить личный рецепт в наше приложение. Тем не менее, вся эта тяжелая работа была бы потеряна, если бы мы не нашли способ показать эти рецепты в основном представлении поиска приложения. Идея высокого уровня здесь заключается в том, чтобы иметь новый шаблон, посвященный, чтобы показать детали User -createDrecipe одновременно индексируя рецепты как из Spoonacular API, так и введенных пользователями.

Как будет работать индексация

Чтобы обеспечить совместимость с методами API, которые мы используем, по сути, вводя ингредиенты и возвращение рецептов, которые используют эти ингредиенты, мы сделаем то же самое для введенных пользователя рецептов: если мы ищем ингредиент x и как Spoonacular, так и введенные пользователи Рецепты содержат ингредиент X, мы вернем оба к нашему шаблону джинджи, поэтому оба типа рецептов следуют одной и той же логике индексации.

Очевидно, что это создает другую проблему: в настоящее время наши рецепты перечисляют конечную точку, возвращают только рецепты, которые получают ингредиенты при введении из выпадающего списка: оба компонента слишком тесно связаны.

Когда компоненты тесно связаны, приложение становится слишком жестким, и становится все труднее добавлять новые функции.

Целая функциональность нашего приложения, в настоящее время зависит от очень плохого соединения передних компонентов и нашей бэкэнд-конечной точки, и предполагает, что пользователь будет выбирать рецепты из раскрывающегося списка. Это будет серьезным недостатком, который будет рассмотрен сразу после того, как мы настроем базовый механизм для рецептов индексации. Посмотрим, как это настроить.

Обогащение основного шаблона джиндзя для отображения рецептов пользователей

Давайте посмотрим, как мы можем обогатить текущий шаблон Jinja, чтобы показать введенные там рецепты пользователя:


         {% for entry in ans %}
     
{% endfor %} {% for entry in userRecipes %}
{% endfor %}

Итак, мы видим, что идея итерации по поводу ответа в основном такая же, как и мы раньше, с основным отличием является использование user_recipe_id Атрибут для определения введенных пользователя рецептов. Кроме того, все может остаться неизменным в коде первого конца. Это определенно не очень элегантно, но это будет хорошо для наших нынешних целей.

При поиске рецепта с курица Как ингредиент (и предполагая, что у нас есть хотя бы один рецепт пользователя, который содержит курицу в качестве ингредиента), это то, что мы получим в пользовательском интерфейсе:

Как мы видим, два из рецептов, которые мы ввели в базу данных в качестве зарегистрированного пользователя, содержали курицу в качестве одного из ингредиентов, и, как следствие, мы можем видеть их в пользовательском интерфейсе вместе с «основными» рецептами, в которых содержались рецепты, в которых содержались Курица тоже. Это означает, что у нас уже есть очень грубая интеграция между внешними данными и «внутренними» данными. Здесь «внутренний» означает, что управляется нашими эндосерами, а также с нами, или, другими словами, именно данные всегда остаются в домене нашей базы данных и данных, которые мы можем контролировать и управлять по своему желанию, в отличие от предстоящих данных Из внешних источников, которые мы не можем контролировать.

Прежде чем мы углубимся в то, как обрабатывать детали введенного рецепта пользователя, давайте сначала сосредоточимся на изменениях, внесенных на стороне колбы, чтобы создать этот дополнительный список.

Как адаптировать нашу конечную точку для размещения пользовательских рецептов

Изменения должны произойти на get_recipe () конечная точка, которая теперь так:

@app.route('/', methods=['GET', 'POST'])
def get_recipe():
    ingredients_searched = []
    chip_ingredients = []
    user_recipes = []
    suggestions_as_json = {"searches": ingredients_searched}
    chip_ingredients_as_json = {"chipIngredients": chip_ingredients}
    user_recipes_as_json = {"userRecipes": user_recipes}
    if request.method == 'POST':
        search_suggestions = select(prod for prod in SearchSuggestion).order_by(lambda prod: desc(prod.id))[:5]
        for entry in search_suggestions:
            ingredients_searched.append(entry.ingredient)
        suggestions_as_json = {"searches": ingredients_searched}

        ing_suggestions = select(prod for prod in IngredientChip)
        for entry in ing_suggestions:
            chip_ingredients.append(entry)
        chip_ingredients_as_json = {"chipIngredients": chip_ingredients}
        ingredients = ",".join(map(lambda db_entry: db_entry.ingredient, chip_ingredients))
        print "Ingredients ",ingredients
        recipes = UserCreatedRecipe.select(
            lambda recipe1: ingredients in recipe1.ingredients) # if ingredients in userRecipe.ingredients
        print "Recipes",recipes
        for recipe_from_user in recipes:
            print recipe_from_user.name
            user_recipes.append({"name":recipe_from_user.name,"ingredients":recipe_from_user.ingredients,
                                 "instructions":recipe_from_user.instructions,
                                 "user_recipe_id": recipe_from_user.id})
        user_recipes_as_json = {"userRecipes": user_recipes}
        print user_recipes_as_json
        content = requests.get(
            +
            convert_input(ingredients) +
            + API_KEY)
        json_response = json.loads(content.text)
        return render_template("recipes_list.html", ans=json_response, searchHistory=suggestions_as_json,
                               chipIngredients=chip_ingredients_as_json, userRecipes=user_recipes_as_json['userRecipes'])
    else:
        delete(ingredient for ingredient in IngredientChip)
        return render_template("recipes_list.html", searchHistory=suggestions_as_json,
                               chipIngredients=chip_ingredients_as_json, userRecipes=user_recipes_as_json['userRecipes'])

Прежде чем мы даже продолжим анализ логики, здесь что-то уже не так: этот код невозможно понять, это фактически зверь на 38 линии !! Ни один программист не может эффективно сохранять 38 линий в своих головах в любое время во время кодирования, поэтому давайте разделим эту конечную точку на более логические функции:

  • Получить предложения поиска: обрабатывать логику предложений поиска
  • Получить ингредиенты: делает то же самое для ингредиентов
  • Обработка рецептов пользователей: позаботитесь о логике для обработки рецептов пользователя

После этого и определения этих строительных блоков наша конечная точка теперь выглядит так:

@app.route('/', methods=['GET', 'POST'])
def get_recipe():
    ingredients_searched = []
    chip_ingredients = []
    user_recipes = []
    suggestions_as_json = {"searches": ingredients_searched}
    chip_ingredients_as_json = {"chipIngredients": chip_ingredients}
    user_recipes_as_json = {"userRecipes": user_recipes}
    if request.method == 'POST':
        suggestions_as_json = handle_searches(ingredients_searched, suggestions_as_json)
        chip_ingredients_as_json, ingredients, recipes = retrieve_ingredients_from_api_and_users(chip_ingredients,                                                                                       chip_ingredients_as_json)
        json_response, user_recipes_as_json = build_user_plus_api_json_responses(ingredients, recipes, user_recipes, user_recipes_as_json)
        return render_template("recipes_list.html", ans=json_response, searchHistory=suggestions_as_json,
                               chipIngredients=chip_ingredients_as_json, userRecipes=user_recipes_as_json['userRecipes'])
    else:
        delete(ingredient for ingredient in IngredientChip)
        return render_template("recipes_list.html", searchHistory=suggestions_as_json,
                               chipIngredients=chip_ingredients_as_json, userRecipes=user_recipes_as_json['userRecipes'])

Из 38 строк мы сократили до 14, и, что более важно, мы получили много читаемости: быстрый взгляд на небольшие функции внутри конечной точки, немедленно предоставляя больше информации о том, что происходит в каждом из них: это увеличивает поддерживаемость нашей кодовой базы Анкет Новый разработчик, который сначала увидит этот код, теперь больше контролирует то, что он может узнать из чтения самого кода, и будет более уверенно, когда придет время внести изменения. Дело не в том, чтобы полностью резать строки, а в том, чтобы сохранить внутреннюю структуру кода под нашим контролем, чтобы он не вышел из -под контроля: этот процесс должен быть сделан Постоянно Анкет

Теперь заглядывая в функцию, ответственную за поиск ингредиентов из введенных пользователей рецептов:

def retrieve_ingredients_from_api_and_users(chip_ingredients):
    ing_suggestions = select(prod for prod in IngredientChip)
    for entry in ing_suggestions:
        chip_ingredients.append(entry)
    chip_ingredients_as_json = {"chipIngredients": chip_ingredients}
    ingredients = ",".join(map(lambda db_entry: db_entry.ingredient, chip_ingredients))
    print "Ingredients ", ingredients
    recipes = UserCreatedRecipe.select(
        lambda recipe1: ingredients in recipe1.ingredients)  # if ingredients in userRecipe.ingredients
    print "Recipes", recipes
    return chip_ingredients_as_json, ingredients, recipes

Мы видим, что, аналогично ранее, мы делаем выбор, через пони, который в данном случае будет отфильтровать пользователь введенных рецептами по теми, которые содержат введенный ингредиент в качестве ввода в их списке ингредиентов, и мы просто возвращаем его в результате эта функция.

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

def build_user_plus_api_json_responses(ingredients, recipes, user_recipes, user_recipes_as_json):
    for recipe_from_user in recipes:
        print recipe_from_user.name
        user_recipes.append({"name": recipe_from_user.name, "ingredients": recipe_from_user.ingredients,
                             "instructions": recipe_from_user.instructions,
                             "user_recipe_id": recipe_from_user.id})
    user_recipes_as_json = {"userRecipes": user_recipes}
    print user_recipes_as_json
    content = requests.get(
        +
        convert_input(ingredients) +
        + API_KEY)
    json_response = json.loads(content.text)
    return json_response, user_recipes_as_json

Эта функция отражается над введенным пользователем рецептами и извлекает рецепты из API для создания ответов JSON, и возвращает их обоих в качестве кортежа, и, как только это будет возвращено, мы можем просто использовать его, чтобы передать эти результаты в наш шаблон Jinja, который будет Дайте нам именно те результаты, которые мы впервые исследовали в начале поста. Как это, идея сделать функцию пользователя, который может ввести свои собственные рецепты в нечто более действенное, завершено!

Вывод

Сейчас, когда эта функция превратилась в нечто более действенное, затем мы сосредоточимся на переработке поиска, который у нас в настоящее время есть на статическом массиве на стороне JavaScript, в нечто более динамичное, обработанное на стороне флезы. Это позволит нам искать рецепты, которые содержат определенные ингредиенты, которые были введены только пользователями, чтобы сделать наш тип-головы более полезными и хорошо интегрированными как с внешними данными API, так и с данными, используемыми пользователем.

Серия колбы (13 части серии)

Оригинал: “https://dev.to/brunooliveira/flask-part-12-indexing-user-entered-recipes-in-the-main-search-page-2fj1”