My project is based on Pyramid.
Pyramid's default scaffold is very simple: view.py, models.py, and so on.
I created some directories to replace them. For example:
view.py --> view directory
models.py --> model directory
Then I create a file named login.py:
from pyramid.httpexceptions import HTTPForbidden
from pyramid.response import Response
from pyramid.view import view_config
import logging
from ..model import (
DBSession,
DynUser,
)
log = logging.getLogger(__name__)
def find_user(account):
#user = None
try:
user = DBSession.query(DynUser).filter(DynUser.username==account).first()
#one = DBSession.query(MyModel).filter(MyModel.name=='one').first()
except ValueError:
#log.warning("invalidate id %s input." % request.matchdict['id'])
log.warning("invalidate id %s input.")
except Exception:
log.error("database error!")
if not user:
return HTTPForbidden()
return dict(user=user)
I have imported DBSession. Why do I still get this error?
tip
--------------------------------------------------------------------------
Undefined variable from import: DBSession
Undefined variable from import: DBSession
DBSession Found at: dyncms.model.meta
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
You didn't mention it, but I'll assume you moved models.py to model/__init__.py.
from ..models only works if login.py is in a subdir (like login/login.py). If it's not the case, you should use from .models import.
In model directory
__init__.py
# package
from .meta import DBSession
from .meta import Base
from .book import Book
meta.py
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (
scoped_session,
sessionmaker,
)
from zope.sqlalchemy import ZopeTransactionExtension
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
Related
I am trying to create a database from SQLAlchemy. I am using Postgres as my database. When trying to create the database I get import error in from . import models in main.py file. I am following this link
https://fastapi.tiangolo.com/tutorial/sql-databases/#create-the-database-tables
Main.py
from re import S
from typing import Optional
from fastapi import Body, FastAPI,Response,status,HTTPException,Depends
from numpy import append
from pkg_resources import yield_lines
from pydantic import BaseModel
from random import randrange
import psycopg2
from psycopg2.extras import RealDictCursor
import time
from sqlalchemy.orm import Session
from . import models
from .database import engine,SessionLocal
models.Base.metadata.create_all(bind = engine)
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = 'postgresql://postgres:123#Localhost/fastapi'
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit = False, autoflush = False , bind= engine)
Base = declarative_base()
models.py
from sqlalchemy import Column, Integer,String,Boolean
from .database import Base
from sqlalchemy.sql.expression import null
class Post(Base):
__tablename__ = "posts"
id = Column(Integer,primary_key=True,nullable = False)
title = Column(String,nullable = False)
content = Column(String,nullable = False)
published = Column(Boolean, default = True)
from . import models
ImportError: attempted relative import with no known parent package
Replace: from .database import Base
Into --> from database import Base
I am Facing Issue With put Method it shows me 200 Successfully response but it does not updated on database.
database.py:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
sql_database_url="mysql://root:zeehan#localhost:3306/mybookstore"
engine=create_engine(sql_database_url)
sessionLocal=sessionmaker(autocommit=False,bind=engine)
base=declarative_base()
This is my database file
main.py:
from typing import Optional
from fastapi import FastAPI,Query,Depends,Path,HTTPException
from sqlalchemy import Column,String,Integer,Float
from pydantic import BaseModel, errors
from sqlalchemy.orm import Session, query, session
from sqlalchemy import create_engine
from sqlalchemy.sql.schema import MetaData
from sqlalchemy import databases
from book_Database import engine,sessionLocal,base,sessionmaker
app=FastAPI()
class BookStore(base):
__tablename__="mybookstore"
id=Column(Integer,primary_key=True,index=True,autoincrement=True)
name=Column(String(255),index=True)
author=Column(String(225))
rating=Column(Float)
description=Column(String(225))
class BookStoreSchema(BaseModel):
name:str
author:str
rating:float
description:str
class BookStoreUpdateSchema(BaseModel):
id=int
name:str
author:str
rating:float
description:str
class Config:
orm_model=True
def get_bookdb():
db=sessionLocal()
try:
yield db
finally:
db.close()
base.metadata.create_all(bind=engine)
#app.get("/books")
def getstudent(db:Session=Depends(get_bookdb)):
return db.query(BookStore).all()
#app.get("/books/{id}")
def getstudent_by_name(id:int,db:Session=Depends(get_bookdb)):
bookstore = db.query(BookStore).get(id)
return bookstore
#app.post("/create-book")
def creatBook(*,BookStoreSchema:BookStoreSchema,rating :float=Query( None,gt=0,lt=6)):
bookstore = BookStore( name=BookStoreSchema.name,author=BookStoreSchema.author,rating=BookStoreSchema.rating ,description=BookStoreSchema.description)
with Session(bind=engine) as session:
session.add(bookstore)
session.commit()
return bookstore
#app.put("/update-book/{id}")
def update_student(id:int,bookstore:BookStoreUpdateSchema,db:Session=Depends(get_bookdb)):
bookstore = db.query(BookStore).get(id)
BookStore.name = bookstore.name
BookStore.author=bookstore.author
BookStore.rating=bookstore.rating
BookStore.description=bookstore.description
db.commit()
return bookstore
When I try to run this API using UVICorn I was running successfully but there is some issue with the put method. It shows successful response but it does not update the content of database.
In your database.py file, declarative_base() returns a class so instead of base make it Base
Base = declarative_base()
class BookStore(Base):
pass
In your main.py file for createBook function try something simple first:
#app.post("/create-book")
def creat_a_book(new_book: BookStoreSchema, db: Session = Depends(get_bookdb)):
book = BookStore(**new_book())
db.add(book)
db.commit()
db.refresh(book)
return book
change the variable name of the updated book in your update function arguments, and in your schema definition change orm_model to orm_mode let's call it updated_book
Try grabbing your book from bookstore like this:
bookstore = db.query(BookStore).filter(BookStore.id == id)
and update the book with the update function
bookstore.update(updated_book.dict(), synchronize_session=False)
db.commit()
I am still learning flask and I have created an restful API with SQLAlchemy. The app is getting to be big and I would like to split it up into multiple files. When I separate the routes section from the main file, the app starts complaining about the SQL modules not being found. I have added all the imports to the routes file and it doesn't seem to help either. The error I am getting is:
module>
Session.configure(bind=engine)
NameError: name 'engine' is not defined
How can I get the Alchemy module to talk to admin.py?
app
app.py
admin
__init__.py
admin.py
######################## admin.py ########################
from flask import Flask, request, jsonify, Blueprint, render_template
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
import json
import logging
admin = Blueprint("admin", __name__)
#initialize Session
Session = sqlalchemy.orm.sessionmaker()
Session.configure(bind=engine)
session = Session()
employee_schema = EmployeeSchema()
#create Employee
#admin.route('/', methods=['POST'])
def add_employee():
..........
#Get Employee
#admin.route('/', defaults={'id': None}, methods=['GET'])
#admin.route('/<id>', methods=['GET'])
..........
#Delete Employee
#admin.route('/<id>', methods=['DELETE'])
def delete_employee(id):
..........
#update Employee
#admin.route('/<id>', methods=['PUT'])
def update_employee(id):
..........
######################## app.py ########################
from flask import Flask, request, jsonify
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
import json
import logging
from admin.admin import admin
#Init app
app = Flask(__name__)
#Allows URL's to be with a trailing / or not
app.url_map.strict_slashes = False
app.register_blueprint(admin, url_prefix="/")
#Gets password info from json file
..........
# Define the MariaDB engine using MariaDB Connector/Python
engine = sqlalchemy.create_engine(f"mariadb+pymysql://{DB_USER}:{DB_PASS}#{DB_HOST}:{DB_PORT}/{DB}")
Base = declarative_base()
class Employee(Base):
__tablename__ = 'employees'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
firstname = sqlalchemy.Column(sqlalchemy.String(length=100))
lastname = sqlalchemy.Column(sqlalchemy.String(length=100))
active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
Base.metadata.create_all(engine)
#initialize Session
Session = sqlalchemy.orm.sessionmaker()
Session.configure(bind=engine)
session = Session()
I suppose your error is traceable to admin.py, because in there you want to initialize the session again using enginewhich is not known in admin.py.
A possible solution would be to import engine from app.py.
Found a workaround. I created a init file inside the folder instead and it is now working.
I am trying to setup a database just like in a tutorial but I am getting a programming error that a table doesn't exist when I'm trying to add a User
This is the file that errors (database.py):
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine(
"mysql+pymysql://testuser:testpassword#localhost/test?charset=utf8",
connect_args = {
"port": 3306
},
echo="debug",
echo_pool=True
)
db_session = scoped_session(
sessionmaker(
bind=engine,
autocommit=False,
autoflush=False
)
)
Base = declarative_base()
def init_db():
import models
Base.metadata.create_all(bind=engine)
from models import User
db_session.add(
User(username="testuser", password_hash=b"", password_salt=b"", balance=1)
)
db_session.commit()
print("Initialized the db")
if __name__ == "__main__":
init_db()
To init the database (create the tables) I just run the file.
It errors when it creates the test user.
Here is models.py:
from sqlalchemy import Column, Integer, Numeric, Binary, String
from sqlalchemy.orm import relationship
from database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
username = Column(String(16), unique=True)
password_hash = Column(Binary(32))
password_salt = Column(Binary(32))
balance = Column(Numeric(precision=65, scale=8))
def __repr__(self):
return "<User(balance={})>".format(balance)
I tried:
Committing before adding users (after create_all)
Drop existing tables from the database (although it seems like the table never gets committed)
from models import User instead of import models (before create_all)
Sorry if there are so many simillar questions, I promise I scavenged for answers, but it's always silly mistakes I made sure I didn't make (or atleast the ones I saw).
I am using MariaDB.
Sorry for long post, many thanks in advance.
The Base in database.py isn't the same Base that is imported into models.py.
A simple test is to put a print('creating Base') function call just above the Base = declarative_base() statement, and you'll see it is being created twice.
Python calls the module that is being executed '__main__', which you know as you have the if __name__ == '__main__' conditional at the bottom of your module. So the first Base that is created is __main__.Base. Then, in models.py, from database import Base causes the database module to be parsed again, creating database.Base in the namespace, and that is the Base from which User inherits. Then back in database.py, the Base.metadata.create_all(bind=engine) call is using the metadata from __main__.Base which has no tables in it, and as such creates nothing.
Don't execute out of the module that creates the Base instance. Create another module called main.py (or whatever), and move your init_db() function there and import Base, db_session and engine from database.py into main.py. That way, you are always using the same Base instance. This is example of main.py:
from database import Base, db_session, engine
from models import User
def init_db():
Base.metadata.create_all(bind=engine)
db_session.add(
User(username="testuser", password_hash=b"", password_salt=b"", balance=1)
)
db_session.commit()
print("Initialized the db")
if __name__ == "__main__":
init_db()
Declare Base class once(for each database) & import it to all modules which define table classes (inherited from Base)
For Base (a metaclass) to scan & find out all classes which are inherited from it, we need to import all the modules where such table classes (inherited from Base) are defined to module where we call Metadata.create_all(engine).
You need to import the relevant model where you call "Base.metadata.create_all". Example below to create user table
from ModelBase import Base
from UserModel import User
def create_db_schema(engine):
Base.metadata.create_all(engine,checkfirst=True)
Whenever I try to import init db in the python console:
>>from app.database import init_db
>>init_db()
init db
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "app\database.py", line 18, in init_db
import models
ImportError: No module named models
This is the content of my app.database function:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from config import SQLALCHEMY_DATABASE_URI
engine = create_engine(SQLALCHEMY_DATABASE_URI, convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
print "init db"
import models
Base.metadata.create_all(bind=engine)
Why is it like this?
UPDATE: This is the structure of my project.
app/
filebase/
init.py
models.py
users/
init.py
models.py
projects/
init.py
models.py
init.py
database.py (this is where the init_db was defined
As for the structure on why it looked like that, the reason is to make the project modular in its form.
You need the parent directory of models.py (or, of the models package) to be in your sys.path. You can put it there in your console session, or, in the shell, add it to environment variable PYTHON_PATH so it will be set at entry to the console session.