SQLAlchemy / WTForms QuerySelectField - sqlalchemy

I am attempting to use WTForms with the SQLAlchemy extension on a Pyramid application.
I have done:
from wtforms import Form, TextField,TextAreaField, validators
from wtforms.ext.sqlalchemy.fields import QuerySelectField
from app.models import DBSession
from app.models import ParentModel
class NewChild(Form):
title = TextField('Title:', [validators.Required()])
intro = TextAreaField('Introduction:')
body = TextAreaField('Body:')
parent = QuerySelectField(query_factory=DBSession().query(ParentModel).all)
DBSession is defined as
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
The query seems to work, but the display in my template is reading
<app.models.ParentModel object at 0x9xxx>
or some such. What am I doing wrong?

You need to define a a __str__ method on ParentModel

Related

SQLModel: sqlalchemy.exc.ArgumentError: Column expression or FROM clause expected,

I am using the SQLModel library to do a simple select() like described on their official website. However I am getting Column expression or FROM clause expected error message
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine, select
from models import Hero
sqrl = f"mysql+pymysql:///roo#asdf:localhost:3306/datab"
engine = create_engine(sqrl, echo=True)
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
def select_heroes():
with Session(engine) as session:
statement = select(Hero)
results = session.exec(statement)
for hero in results:
print(hero)
def main():
select_heroes()
if __name__ == "__main__":
main()
this is my models/Hero.py code:
from datetime import datetime, date, time
from typing import Optional
from sqlmodel import Field, SQLModel
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
secret_name: str
age: Optional[int] = None
created: datetime
lastseen: time
when I run app.py I get the sqlalchemy.exc.ArgumentError: Column expression or FROM clause expected, got <module 'models.Hero' from '/Users/dev/test/models/Hero.py'>. message
The error message <Column expression or FROM clause expected, got module 'models.Hero' from '/Users/dev/test/models/Hero.py'> tells us:
SQLModel / SQLAlchemy unexpectedly received a module object named models.Hero
that you have a module named Hero.py
The import statement from models import Hero only imports the module Hero. Either
change the import to import the model*
from models.Hero import Hero
change the code in select_heroes to reference the model†
statement = select(Hero.Hero)
* It's conventional to use all lowercase for module names; following this convention will help you distinguish between modules and models.
† This approach is preferable in my opinion: accessing the object via the module namespace eliminates the possibility of name collisions (of course it can be combined with lowercase module names).

Convert plain text / wiki syntax to HTML with Jira ScriptRunner (show bullet points, checkmark smileys, etc.)

I am trying to retrieve the text of the most recent comment I typed in a JIRA issue page, here is a screenshot of the most recent comment I typed:
I am using this code in the Jira script runner to retrieve the last comment I have typed in:
import com.atlassian.jira.component.ComponentAccessor
import java.text.SimpleDateFormat
import com.opensymphony.util.TextUtils
import com.atlassian.jira.issue.comments.*
import org.w3c.dom.*;
import javax.xml.parsers.*;
import groovy.xml.*
import grrovy.util.*;
import org.xml.sax.InputSource;
import java.io.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
def commentManager = ComponentAccessor.getCommentManager()
Comment comment = commentManager.getLastComment (issue)
if(comment != null) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yy HH:mm", Locale.ENGLISH)
def body = comment.body //.replaceAll("[\r\n]+","\n")
body= """<div style="max-height:100px; overflow:auto;" title="${comment.authorFullName} added last comment - ${dateFormat.format(comment.created)}">
<span style="white-space: pre-wrap;">${TextUtils.htmlEncode(body)}</span>
</div>"""
return body
}
The output of the code above is the following:
I would like the output to be displayed as in its original format meaning, I would like the bullet points to appear, the smiley to appear and the green checkmark to appear as well. I don't want to see the stars and the code color and the smiley abbreviation :) I would like the output to look like the following:
How can I fix this?
You need to render wiki-syntax source to HTML output and use existing wiki renderer.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.RendererManager
import com.atlassian.jira.issue.fields.renderer.JiraRendererPlugin
import com.atlassian.jira.issue.fields.renderer.IssueRenderContext
RendererManager rendererManager = ComponentAccessor.getComponentOfType(RendererManager.class);
JiraRendererPlugin renderer = rendererManager.getRendererForType("atlassian-wiki-renderer");
String lastComment = "* 1\n* 2\n* 3:)\n* {color:#FF0000}(/){color}"
return renderer.render(lastComment, null)

Simply format SQLAlchemy models returned by FastApi endpoint

Suppose I have a simple SQLAlchemy class and a simple Flask o FastAPI implementation like this:
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel
Base = declarative_base()
class A(Base):
__tablename__ = 'as'
my_id = Column(String)
class AModel(BaseModel):
myId:str = None
And a simple endpoint like this:
#app_router.get('/a')
def get_all_a(session:Session = Depends(get_session)):
return session.query(A).all()
How could I ensure that the returned list of this endpoint yields in camelCase like this:
[{'myId': 'id1'},{'myId': 'id2'}, ...]
Note: My application is rather complex, as I also have pagination implemented and some post-processings require a little bit more that just snake_case to camelCase conversion, so the simplest solution would be the best.
I've tried overriding dict() methods and similar stuff with no luck, simply cannot understand how FastAPI processes the results to obtain a JSON.
require a little bit more that just snake_case to camelCase conversion
Well, if you don't use response_model you don't have a lot of choices.
The solution is returning your dict with a conversion from snake_case to camelCase. You have functions that do it recursively.
Why it is the best solution ?
using regex it's super fast, faster than any lib that convert dict to obj like pydantic
If you definitely don't want to do this, well your only solution is using pydantic models, attrs or dataclasses and convert your db query output to one of those models type with camelCase variable name (dirty).
Since you are using fastapi you should use all the power of it.
I would suggest this:
from typing import List
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, Field
from pydantic import parse_obj_as
Base = declarative_base()
class A(Base):
__tablename__ = 'as'
my_id = Column(String)
class AModel(BaseModel):
myId: str = Field(alias="my_id", default=None)
#app_router.get('/a', response_model=List[AModel])
def get_all_a(session:Session = Depends(get_session)):
return parse_obj_as(List[AModel], session.query(A).all())
Keep in mind that having classes variables in CamelCase is not a good practice.
The gold answer would be to not return camel but snake and let your client do the work of conversion if needed.

DJANGO REST - CLASS BASED VIEW - POST,GET requests do not work as they are defined

I've set up a class-based view that handles all the requests
views.py
#Imports
from django.shortcuts import render
from .serializers import UserSerializer
from rest_framework import viewsets
from django.contrib.auth.models import User
from rest_framework.decorators import api_view
from django.http import HttpResponseForbidden
from rest_framework.response import Response
from rest_framework import status
#Imports End
class UserApiView(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request, format=None):
raise HttpResponseForbidden("Get Requests are not allowed here")
def post(self, request, format=None):
if request.is_ajax():
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
raise HttpResponseForbidden("You are not allowed to acess this page")
this is the serializer class ( serializers.py )
from rest_framework import serializers
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username','email','password']
The urls.py are being handel by the DefaultRouter()
from django.urls import include, path
from rest_framework import routers
from .views import UserApiView
router = routers.DefaultRouter()
router.register(r'user',UserApiView,basename="takis")
urlpatterns = [
path('', include(router.urls)),
]
I want the backend to handle the view just as said in the post and get request methods , but they do not seem to get executed.
I can normally access the url , without a forbidden error and it accepts requests even if they are not ajax.
I am not very clear what you are trying to do, what I understand you want to accept post request and reject get. you can extent APIView instead of ModelViewSet
from rest_framework.views import APIView
class UserApiView(APIView):
def get(self, request, format=None):
# handle get
def post(self, request, format=None):
# handle post
A Viewset is only usefull if you overwrite one of these methods.
create()
retrieve()
update()
partial_update()
destroy()
list()
If you need to overwrite get and post method you are better off with APIView or GenericAPIView.

Automap multiple databases with Flask-SQLAlchemy

I have an app currently working fine Automapping one database, but I need to access another database now as well. I tried to follow the Flask-SQLAlchemy documentation here: http://flask-sqlalchemy.pocoo.org/2.1/binds/, but it doesn't seem to work with the automap_base.
The only changes I made were creating SQLALCHEMY_BINDS and adding the __bind_key__ in models.py. The error I get is
sqlalchemy.exc.ArgumentError: Mapper Mapper|Table2|table2 could not assemble any primary key columns for mapped table 'table2'
However, both tables have a primary key column, and if I get rid of SQLALCHEMY_BINDS, set the URI to that of db2, and only have table2 in models.py, everything works fine.
I'm clearly doing something wrong, but I have no idea what it is. It looks like Flask is still looking for table2 in db1. I think my problem is that some change needs to be made to __init__.py as well, but I don't know what that would be.
config.py
SQLALCHEMY_DATABASE_URI = 'mysql://user#host/db1'
SQLALCHEMY_BINDS = {
'otherDB': 'mysql://user#host/db2',
}
__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.ext.automap import automap_base
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
db.Model = automap_base(db.Model)
from app import models
db.Model.prepare(db.engine, reflect=True)
models.py
class Table1(db.Model):
__tablename__ = 'table1'
class Table2(db.Model):
__bind_key__ = 'otherDB'
__tablename__ = 'table2'
Automap is a extension of sqlalchemy to reflect an existing database into a new model. It has not been baked into flask-sqlalchemy. Plz see the issue here. You can connect to multiple databases with Flask-SQLAlchemy like this:
__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
from app import models
if __name__ == "__main__":
# show the table schema
print m3.Table1.__table__.c
print m3.Table2.__table__.c
models.py
db.reflect() # reflection to get table meta
class Table1(db.Model):
__tablename__ = 'table1'
class Table2(db.Model):
__tablename__ = 'table2'
__bind_key__ = 'otherDB'