Estoy siguiendo este tutorial para crear un sistema de autenticación basado en JWT.

App.py:

from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'd0cad49580952003e6ae01499c7bb190a4b4f9a5babd866f47064707f7b78506'

api = Api(app)
db = SQLAlchemy(app)


@app.before_first_request
def create_tables():
    db.create_all()


import resources, models

api.add_resource(resources.UserRegistration, '/registration')


if __name__ == '__main__':
    app.run()

Models.py:

from app import db


class UserModel(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    password = db.Column(db.String(150), nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)

    def __init__(self, name, password, email):
        self.name = name
        self.password = password
        self.email = email

    @classmethod
    def find_by_username(cls, username):
        return cls.query.filter_by(username=username).first()

    def save_to_db(self):
        db.session.add(self)
        db.session.commit()

Resources.py:

from flask_restful import Resource, reqparse
from models import UserModel


class UserRegistration(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('name', help='This field cannot be blank', required=True)
        parser.add_argument('email', help='This field cannot be blank', required=True)
        parser.add_argument('password', help='This field cannot be blank', required=True)

        data = parser.parse_args()

        if UserModel.find_by_username(data['name']):
            return {'message': 'User {} already exists'.format(data['name'])}

        new_user = UserModel(
            name=data['name'],
            password=data['password'],
            email=data['email']
        )
        try:
            new_user.save_to_db()
            return {
                'status': 'User {} was created'.format(data['username'])}

        except:
            return {'message': 'Something went wrong'}, 500

Cuando ejecuto app.py, aparece el siguiente error:

Traceback (most recent call last):
  File "G:\python\PycharmProjects\vumonic\app.py", line 19, in <module>
    import resources, models
  File "G:\python\PycharmProjects\vumonic\resources.py", line 2, in <module>
    from models import UserModel
  File "G:\python\PycharmProjects\vumonic\models.py", line 1, in <module>
    from app import db
  File "G:\python\PycharmProjects\vumonic\app.py", line 21, in <module>
    api.add_resource(resources.UserRegistration, '/registration')
AttributeError: module 'resources' has no attribute 'UserRegistration'

Este error desaparece cuando elimino from models import UserModel de resources.py.

No puedo averiguar el motivo del error.

Estoy usando Flask == 1.1.2, Flask-SQLAlchemy == 2.4.4 y Flask-RESTful == 0.3.8

Esta es la primera vez que estoy desarrollando una API, por lo que se agradecería cualquier ayuda.

0
Ayush Agarwalla 28 jul. 2020 a las 14:13

1 respuesta

La mejor respuesta

Se enfrenta a un problema de importación circular.

Cuando Python importa un módulo, comprueba el registro del módulo para ver si el módulo ya se importó. Si el módulo ya estaba registrado, Python usa ese objeto existente de la memoria caché. El registro del módulo es una tabla de módulos que se han inicializado e indexado por el nombre del módulo. Se puede acceder a esta tabla a través de sys.modules.

Si no estaba registrado, Python encuentra el módulo, lo inicializa si es necesario y lo ejecuta en el espacio de nombres del nuevo módulo.

Para saber más sobre la importación circular puede leer el artículo:

https://stackabuse.com/python-circular-imports/

https://www.stefaanlippens.net/circular-imports-type-hints-python.html

Este tutorial de Miguel Grinberg es un salvador de vidas https://www.youtube.com/watch?v=NH-8oLHUyDc&t= 3205s

1
Tasnuva 28 jul. 2020 a las 15:28