Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using proper file structure with SQLAlchemy and how to add data to db

I am trying to build a simple blogging platform to learn Python and Flask. I am using SQLAlchemy to connect to a Postgres db hosted on Heroku and flask_s3 to serve static files from an AWS bucket. Im mostly following along from this:

https://gist.github.com/mayukh18/2223bc8fc152631205abd7cbf1efdd41/

All was going well, it is correctly hosted on Heroku and connceted to AWS S3 bucket, ready to go. I am stuck however on how to add blog posts to the database through some kind of form or route that will allow me to fill in the attributes of a blog post (found in Post in models.py below)

I have html templates that get rendered and the following three files, app.py, manage.py and models.py.

app.py:

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_s3 import FlaskS3

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = '*URI for DB hosted on heroku'
app.config['FLASKS3_BUCKET_NAME'] = 'my S3 bucket on AWS'

db = SQLAlchemy(app)
s3 = FlaskS3(app)

from models import Post

#routes to templates to be rendered

if __name__ == '__main__'
    app.run(debug=True)

manage.py:

from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

from app import app, db

migrate = Migrate(app, db)

manager = Manager(app)
manager.add_command('db', MigrateCommand)

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

and models.py:

from manage import db,app

class Post(db.Model):
    __tablename__ = 'blogposts'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), index=True, unique=True)
    content = db.Column(db.Text, index=True, unique=True)
    date = db.Column(db.DateTime, index=True, unique=True)
    tag = db.Column(db.String(120), index=True, unique=True)
    cover = db.Column(db.String(120), index=True, unique=True)

    def __repr__(self):
        return '<Post: %r>' % (self.title)

my file strucure is:

-blog
  --__pycache__
  --migrations
  --static
  --templates
  app.py
  manage.py
  models.py
  Pipfile
  Pipfile.lock
  Procfile

I want to work on this locally (before I publish anything to Heroku) but have no idea what to do from here. Anyone have advice on how to go about creating a route to add blog posts and saving them to a local Postgres instance before I go about pushing finalized blog posts to Heroku?

the gist I have been following has something like this as a route:

@app.route('/add/')
def webhook():
    #post attributes defined
    p = Post(id = id, title = title, date = datetime.datetime.utcnow, content = content, tag = tag, cover = cover)
    print("post created", p)
    db.session.add(p)
    db.session.commit()
    return "post created"

when I try and run it locally I get the following error so I'm not sure I have the files connecting properly.

File "/Users/Mb/Desktop/datadude/app.py", line 15, in <module>
from models import Post
ImportError: cannot import name 'Post'

Sorry if this is the wrong place for this. If there is a better place to ask for advice let me know.

like image 229
ron_kuby Avatar asked Aug 08 '18 22:08

ron_kuby


People also ask

Which db is used in SQLAlchemy?

Supported Databases. SQLAlchemy includes dialects for SQLite, Postgresql, MySQL, Oracle, MS-SQL, Firebird, Sybase and others, most of which support multiple DBAPIs.

How do I import a database into SQLAlchemy?

To do this, we need to open our terminal to our working directory and follow this process: Initialize the Python interpreter. Next, import the database variable from the __init__.py file where we initialized the SQLAlchemy instance of the object, then create the database.

What does db Create_all () do?

Definition of SQLAlchemy create_all. Sqlalchemy create_all method is used to create a new table into the database. This method will first check whether the table exists in the database or not if suppose it has found an existing table it will not create any table.


1 Answers

The problem exists in circular dependencies.

You could move initializing of SQLAlchemy to models.py. Then only run method init_app on db object in app.py.

models.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Post(db.Model):
    __tablename__ = 'blogposts'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), index=True, unique=True)
    content = db.Column(db.Text, index=True, unique=True)
    date = db.Column(db.DateTime, index=True, unique=True)
    tag = db.Column(db.String(120), index=True, unique=True)
    cover = db.Column(db.String(120), index=True, unique=True)

    def __repr__(self):
         return '<Post: %r>' % (self.title)

app.py

import datetime
from flask import Flask, render_template

from flask_s3 import FlaskS3
from models import db


app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = '*URI for DB hosted on heroku'
app.config['FLASKS3_BUCKET_NAME'] = 'my S3 bucket on AWS'
db.init_app(app)

s3 = FlaskS3(app)
from models import Post


@app.route('/add/')
def webhook():
    #post attributes defined
    p = Post(id = id, title = title, date = datetime.datetime.utcnow, content = content, tag = tag, cover = cover)
    print("post created", p)
    db.session.add(p)
    db.session.commit()
    return "post created"
#routes to templates to be rendered

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

You can read more about it https://github.com/slezica/bleg/blob/master/data/posts/2014-03-08-avoiding-circular-dependencies-in-flask.md

like image 132
Rafał Avatar answered Nov 14 '22 23:11

Rafał