I trying make app with is listing cities from pre-existing postgresql database.
So far I able connect to database and make a query, but results are returned u'string',
Here my models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Woonplaats(Base):
__tablename__ = 'woonplaats'
gid = Column(Integer, primary_key=True)
woonplaatsnaam = Column(String(80))
def __init__(self, woonplaatsnaam=None):
self.woonplaatsnaam = woonplaatsnaam
def __repr__(self):
return '%r' % (self.woonplaatsnaam)
And views.py
from flask import render_template, request
from app import app
from app import db
from app.models import Woonplaats
#app.route('/citylist')
def citylist():
results = db.session.query(Woonplaats).all()
print(results) #only for test
return render_template('city.html', results = results)
In the absence of a __str__ (or __unicode__), a class's __repr__ will be used. When you print out the query set, you end up printing the __repr__ of the woonplaatsnaam column. To print out the value of the column instead, add a __str__ (or __unicode__) method.
def __str__(self):
return self.woonplaatsnaam
# for Python 2.x
def __unicode__(self):
return self.woonplaatsnaam
Related
I have an existing Flask project which uses SQLAlchemy and I wanted to interate an Admin dashboard. Everything worked fine, I managed to enable authentication by using the ModelView Class however if I try to edit or if I try to create a new object of any database model then Flask-Admin throws out the following error:
ValueError: Invalid format string
Here's my Flask-Admin Code:
from flask_admin import Admin
from flask_login import current_user
from flask import redirect, url_for, request
from app import app, db, login
from flask_admin.contrib.sqla import ModelView
from app.auth.models import User
from app.forum.models import thread, post
from app.course.models import Courses
from flask_admin.model import typefmt
from datetime import date
app.config['FLASK_ADMIN_SWATCH'] = 'cerulean'
def date_format(view, value):
return value.strftime('%d.%m.%Y')
MY_DEFAULT_FORMATTERS = dict(typefmt.BASE_FORMATTERS)
MY_DEFAULT_FORMATTERS.update({
type(None): typefmt.null_formatter,
date: date_format
})
class adminmodelview(ModelView):
column_type_formatters = MY_DEFAULT_FORMATTERS
def is_accessible(self):
return (current_user.is_authenticated and current_user.is_admin)
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('home.index'))
admin = Admin(app, name='celis', template_mode='bootstrap3')
admin.add_view(adminmodelview(User, db.session))
admin.add_view(adminmodelview(post, db.session))
admin.add_view(adminmodelview(thread, db.session))
admin.add_view(adminmodelview(Courses, db.session))
Here's the User Model:
class User(UserMixin,db.Model):
id=db.Column(db.Integer,primary_key=True)
username=db.Column(db.String(64),index=True,unique=True)
email=db.Column(db.String(120),index=True,unique=True)
user_role=db.Column(db.String(20))
is_admin=db.Column(db.Integer, default=0)
Region=db.Column(db.String(20))
password_hash=db.Column(db.String(128))
threads=db.relationship('thread',backref='creator',lazy='dynamic')
posts=db.relationship('post',backref='Author',lazy='dynamic')
last_seen=db.Column(db.DateTime,default=datetime.utcnow)
twitter=db.Column(db.String(120),default="N/A")
facebook=db.Column(db.String(120),default="N/A")
instagram=db.Column(db.String(120),default="N/A")
birthdate=db.Column(db.String(120),default="N/A")
Interests=db.Column(db.String(200),default="N/A")
provides_course=db.relationship('Courses',backref="Teacher",lazy='dynamic')
def __repr__(self):
return '<Role:{} Name:{} Id:{}>'.format(self.user_role,self.username,self.id)
def set_password(self,password):
self.password_hash=generate_password_hash(password)
def check_password(self,password):
return check_password_hash(self.password_hash,password)
def get_reset_token(self, expires_sec=1800):
s = Serializer(app.config['SECRET_KEY'], expires_sec)
return s.dumps({'id': self.id}).decode('utf-8')
On searching I found out it could be an issue due to the DateTime presentation, but could not figure out the solution.
bro I had a similar issue to yours, where the exception stemmed from the "date_posted" field in my "Threads" table as by default flask admin reads all data object as a String object so you have to override it as follows in your adminmodelview for example:
form_overrides=dict(date_posted=DateTimeField)
I need to ensure transactionality with flask requests. Is there a way to store a database session per request and use that one?
The easiest way is to create a simple extension for session initialization and commit changes after successful request. Here is an example:
from datetime import datetime
from flask import Flask, current_app, _app_ctx_stack
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
from sqlalchemy import Column, String, Integer
# Base model without connection(see: DBExtension.connect()) and a few demo models
Base = declarative_base(cls=DeferredReflection)
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String())
class Log(Base):
__tablename__ = 'log'
id = Column(Integer, primary_key=True, autoincrement=True)
text = Column(String())
# extension for getting db session
class DBExtension:
def __init__(self, app: Flask = None):
self.app = app
if app is not None:
self.init_app(app)
def init_app(self, app):
app.teardown_appcontext(self.teardown)
def connect(self):
# init engine and set into metadata
engine = create_engine(current_app.config['DB_CONNECTION'], echo=True)
Session = sessionmaker(bind=engine)
session = Session()
# create_all - just for demo(init structure...)
Base.metadata.create_all(engine)
Base.metadata.bind = engine
Base.prepare(engine)
return session
def teardown(self, exception):
ctx = _app_ctx_stack.top
if hasattr(ctx, 'session'):
ctx.session.close()
#property
def session(self):
# connect or get active connection
ctx = _app_ctx_stack.top
if ctx is not None:
if not hasattr(ctx, 'session'):
ctx.session = self.connect()
return ctx.session
app = Flask(__name__)
app.config.update({'DB_CONNECTION': 'sqlite:///test.db'}) # sqlite for demo
db = DBExtension(app)
#app.teardown_request
def teardown_request_func(error=None):
# request processing completed(before requests functions, endpoints and other logic)
if not error:
# one more record and commit all changes in one transaction
db.session.add(Log(text='{dt}. teardown_request'.format(dt=datetime.utcnow())))
try:
db.session.commit()
except Exception as e:
print(e)
# do something
#app.before_request
def before_request_func():
# add a new record before request
db.session.add(Log(text='{dt}. before request'.format(dt=datetime.utcnow())))
#app.route('/user/<name>')
def user_route(name: str):
# do something with db session
db.session.add(Log(text='saving user {user}'.format(user=name)))
user = User(name=name)
db.session.add(user)
# session.add(newModel) or session.delete(oneMoreModel) etc.
return 'done' # return without commit. see: teardown_request_func
if __name__ == '__main__':
app.run(host='localhost', port=5000, debug=True)
Run server, open http://localhost:5000/user/DavidBoshton and see logs(BEGIN-...-COMMIT).
All new to Django, I want to write tests for an IndexView and a DetailView in analogy to the Django tutorial.
I have a model that contains a FilerImageField as mandatory field (blank=False).
In order to test my views related to that model, I want to create a model instance programmatically.
I am aware of this question addressing how to create a FilerImageField in code. The problem I run into applying the alleged solution is getting the part right about the image's owner.
def create_exhibitor(name, image_path, active):
filename = 'file'
user = User.objects.get(username='myuser')
with open(image_path) as f:
file_obj = File(f, name=filename)
image = Image.objects.create(
owner=user,
original_filename=filename,
file=file_obj
)
return Exhibitor(name=name, image=image, active=active)
Runnging them tests yields:
Traceback (most recent call last):
...
DoesNotExist: User matching query does not exist.
To me it appears there is no user in the test database.
So my question is twofold really:
Do I need a user there to create an instance of the model containing the FilerImageField?
If so, how do I create one for test purposes?
I'm finally doing it like so:
from django.test import TestCase
from django.contrib.auth.models import User
from django.core.files.uploadedfile import SimpleUploadedFile
from .models import Exhibitor
class TestCase():
su_username = 'user'
su_password = 'pass'
def setUp(self):
self.superuser = self.create_superuser()
def create_superuser(self):
return User.objects.create_superuser(self.su_username, 'email#example.com', self.su_password)
def create_exhibitor(self):
name = 'eins'
active = True
image_file = SimpleUploadedFile(
'monkey.jpg', b'monkey', content_type="image/jpeg"
)
return Exhibitor(name=name, image=image_file, active=active)
I've made a model with file that is uploaded to custom path (not in MEDIA_ROOT). So it's some kind like protected file.
Now I need to change it's representation in admin details. It shows a path relative to MEDIA_URL. I need to change that, to show a URL to an application view which generates a proper URL.
So, what is the best way to display link, and only in objects details in admin?
Here is the way I did it:
models.py
class SecureFile(models.Model):
upload_storage = FileSystemStorage(
location=settings.ABS_DIR('secure_file/files/'))
secure_file = models.FileField(verbose_name=_(u'file'),
upload_to='images', storage=upload_storage)
widgets.py
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
class AdminFileWidget(forms.FileInput):
"""A FileField Widget that shows secure file link"""
def __init__(self, attrs={}):
super(AdminFileWidget, self).__init__(attrs)
def render(self, name, value, attrs=None):
output = []
if value and hasattr(value, "url"):
url = reverse('secure_file:get_secure_file',
args=(value.instance.slug, ))
out = u'{}<br />{} '
output.append(out.format(url, _(u'Download'), _(u'Change:')))
output.append(super(AdminFileWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
admin.py
class SecureFileAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SecureFileAdminForm, self).__init__(*args, **kwargs)
self.fields['secure_file'].widget = AdminFileWidget()
class Meta:
model = SecureFile
class SecureFileAdmin(admin.ModelAdmin):
form = SecureFileAdminForm
I'm studying now main concepts of flask and flask-sqlalchemy. Keeping in my mind info from the tutorial (intro and contexts) I'm trying to create a simple database.
My Flask app is strucured as follows:
./db/
./db/models.py
./main.py
The contents of the files is as follows:
./main.py:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object(__name__)
from db.models import create_app
dbapp = create_app()
with dbapp.test_request_context():
from db.models import db, mumsUsers
db.create_all()
db.session.rollback()
admin = mumsUsers("admin", "admin#example.com")
db.session.add(admin)
db.session.commit()
./db/models.py:
from flask.ext.sqlalchemy import SQLAlchemy
from flask import Flask, current_app
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db.init_app(app)
return(app)
class mumsUsers(db.Model):
__tablename__ = 'mumsUsers'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(80), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
When I check the sqlite database, I see that sqlalchemy is trying to send commit() twice. So I have to remove the unique=True parameter in order to stop application crash. Meantime when I run the following commans from the python shell:
admin = mumsUsers('admin', 'admin#example.com')
db.session.add(admin)
db.session.commit()
only one record appears (as it is expected).
Therefore my question is how to prevent double call for commit()?
Update
The appeared problem has been caused by my fault, while making looped imports. Indeed I didn't notice I called import for the application package.
Therefore please ignore this post.
The caused problem has been related to looped imports.
Please check what you import before asking.