Im writing a web app in flask that displays bus stops pulled from an api.

i have a form on index.html where a user can input a stop number, that number gets picked up in views.py where the function also runs a task through celery to fetch the api data:

from flask import render_template, request
from app import app

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/stopno', methods=['POST'])
def stopno():
    stopid = request.form['input']
    from app.tasks import apidata
    apidata.delay()
    return render_template('action.html')

here is my tasks.py:

from celery import Celery
import json
import requests
import time

ac = Celery('tasks', broker='amqp://localhost')

@ac.task(name='tasks.apidata')
def apidata():
    from views import stopno
    api = '*apiurl*:' + str(stopid)
    saveinfo = 'static/stop' + str(stopid)+ '.json'

    r = requests.get(api)
    jsondata = json.loads(r.text)

    with open(saveinfo, 'w') as f:
        json.dump(jsondata, f)

I am importing stopno from views into tasks so i can search the api for the specified stop, currently when a user inputs a stop number the action.html loads fine and displays the stop number the user inputs but no new file or data is created for the stop number and celery throws an error saying

ImportError: No module named views

structure of my project is

|____run.py
|____app
| |______init__.py
| |____views.py
| |____tasks.py
| |____static
| | |____json
| |____templates
| | |____action.html
| | |____index.html

Solution 1:

You are trying to do a relative import but you are not making it explicitly relative, which may or may not work, and which can cause unexpected errors. You should make your import explicitly relative with:

from .views import stopno

This way you don't have to worry about reproducing the entire path to the module.