I did ask this question but i am gonna ask it again since didn't get any response
I am developing a simple flask app with Projects and Tickets tables and they look like following
class Projects(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable = False)
description = db.Column(db.Text, nullable = False)
created_by_id = db.Column(db.Integer, nullable = False)
expert_id = db.Column(db.Integer, db.ForeignKey('users.id'))
def __repr__(self):
return f"{self.title}"
class Tickets(db.Model):
id = db.Column(db.Integer,primary_key=True)
title = db.Column(db.String(100),nullable=False)
ticket_text = db.Column(db.Text,nullable=False)
date_posted = db.Column(db.DateTime,nullable=False,default=datetime.utcnow)
created_by_id = db.Column(db.Integer, nullable=False)
expert_id = db.Column(db.Integer, db.ForeignKey('users.id'),nullable=False)
project_id = db.Column(db.Integer, db.ForeignKey('projects.id'),nullable=False)
projects = db.relationship('Projects', backref='ticketso', lazy=True)
def __repr__(self):
return f"Tickets('{self.title}','{self.date_posted}')"
Basically it is one Project can have many Tickets but when I query it
#app.route('/project/<project_id>')
def project(project_id):
project = Projects.query.get_or_404(project_id)
return render_template('project.html',title=project.title, project=project)
and trying to display it
<div class="jumbotron">
<h1>{{ project.title }}</h1>
<p>{{ project.description }}</p>
<p><a class="btn btn-primary btn-md">{{ project.created_by_id }}</a></p>
<p><a class="btn btn-primary btn-lg">{{ project.ticketso }}</a></p>
</div>
Here project.ticketso supposed to return list of tickets assigned to this Project but instead it returns emtpy list
My tickets.html page can succecfully display Project_id which assigned to that particular ticket
this is how I add ticket to the project
#app.route('/createTicket',methods=['GET','POST'])
def createTicket():
users = Users.query.all()
form = TicketForm()
if form.validate_on_submit():
ticket = Tickets(title=form.title.data,ticket_text=form.ticket_text.data,created_by_id=current_user.username,expert_id= str(form.user_id.data),project_id= str(form.project.data))
db.session.add(ticket)
db.session.commit()
flash('Your ticket has been created', 'success')
return redirect(url_for('index'))
return render_template('createTicket.html',title='Create a Ticket',form=form, users=users)
#app.route('/createProject',methods=['GET','POST'])
def createProject():
users = Users.query.all()
form = ProjectForm()
if form.validate_on_submit():
project = Projects(title = form.title.data, description = form.description.data, created_by_id = current_user.username, expert_id = str(form.user_id.data))
db.session.add(project)
db.session.commit()
flash('You project has been created', 'success')
return redirect(url_for('index'))
return render_template('createProject.html',form = form, users = users)
EDIT:
I am gonna ask this question different way in order to make it clear.
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
addresses = db.relationship('Address', backref='person', lazy=True)
class Address(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), nullable=False)
person_id = db.Column(db.Integer, db.ForeignKey('person.id'),
nullable=False)
The code above I got from flask documentation https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/
It states
backref is a simple way to also declare a new property on the Address class. You can then also use my_address.person to get to the person at that address
So I can access to the person who is in that address, but how do we access to the list of addresses that person has. Because it is one to many relationship, it means one person can have many addresses correct? how do we access them?
You need to "connect" between the 2 tables. You don't need to define expert_id when you create a row. instead you need to point to the Tickets Table by the backref you set.
Change this line
project = Projects(title = form.title.data, description = form.description.data, created_by_id = current_user.username, expert_id = str(form.user_id.data))
To this:
project = Projects(title = form.title.data, description = form.description.data, created_by_id = current_user.username, ticketso=form)
assuming form is the Tickets object you want to point to. Then, you'll be able to get the ID of the Tickets with expert_id
basically, this line projects = db.relationship('Projects', backref='ticketso', lazy=True) creates a "virtual column" in the table you set. In this case is the Projects table (You can also access the Projcts table from Tickets by using the relationship column). Also this two columns are useless. I assume you know how you can access the data without them.
expert_id = db.Column(db.Integer, db.ForeignKey('users.id'),nullable=False)
project_id = db.Column(db.Integer, db.ForeignKey('projects.id'),nullable=False)
Related
I'm using the python's framework pyramid, sqlalchemy for the data and marshmallow to serialize.
I'm want to send a sum of value to the client
I have Challenge and player whom use this challenge, each actions of the player is an event and each events has a duration.
For each challenge, i want to send the sum's duration for each player and also send this value only for one player. I try to use hybrid attribute or pre_dump function but i didn't succeeded
First method : with hybrid attribute
__tablename__ = "Challenge"
id = Column(Integer, primary_key=True)
name = Column(String(255), unique=True, nullable=False)
description = Column(TEXT(length=65535))
map_url = Column(String(255))
end_date = Column(DateTime(timezone=False))
alone_only = Column(Integer)
level = Column(String(255))
scalling = Column(Integer)
draft = Column(Boolean, server_default=text("0"))
admin_id = Column(Integer, ForeignKey("User.id"))
admin = relationship("User", backref="challenge_manager")
event_sum_user = relationship("Events")```
#hybrid_property
def event_sum(self):
return sum(Events.duration for Events in self.event_sum_user)
But i have sum for all user, not by user or for one user
Second method :with pre_dump method
id = fields.Int()
name = fields.Str()
description = fields.Str()
end_date = fields.DateTime()
alone_only = fields.Int()
level = fields.Str()
scalling = fields.Int()
draft = fields.Bool()
admin = fields.Nested(UserSchema)
admin_id = fields.Int(load_only=True)
event_sum = fields.Int(dump_only=True)
#pre_dump
def get_eventsum(self,data, **kwargs):
data["event_sum"] = DBSession.query(func.sum(Events.duration)).filter(Events.challenge_id==data["id"]).filter(Events.user_id==1).first()
return data```
With this method, i've have an error TypeError: 'Challenge' object is not subscriptable'
The purpose of this is to send with each challenge the total duration realise by a user or for each user on the challenge : id_user and total duration.
Thanks for your help
Marilyn
I'm building an app for rating beers at an event. The beers one can rate should be added to a table, as well should the event be added to another table and the beers and the event should be connected. Since at an event there is more than just one beer to be tasted and a beer can be tasted at multiple events, I want to make a m:n-relationship. I'm doing this with python3, I'm using flask and flasksqlalchemy. I'm using an sqlite-database.
The model I builded sofar looks like this:
#association table
event_beer = db.Table('event_beer',
db.Column('event_id', db.Integer, db.ForeignKey('event.id'), primary_key=True),
db.Column('beer_id', db.Integer, db.ForeignKey('beer.id'), primary_key=True))
class Event(db.Model):
__tablename__ = 'event'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
def __str__(self):
return f'{name}'
class Beer(db.Model):
__tablename__ = 'beer'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
event = db.relationship('Event', secondary=event_beer)
def __str__(self):
return f'{self.name}, {self.event}'
I omitted a few Columns which don't have any Foreign Keys or so for the sake of simplicity. The code which is executed when I want to save the recorded data is:
event = Event(name = 'event_name')
beer1 = Beer(name = 'beerone')
beer2 = Beer(name = 'beertwo')
beer1.event.append(event)
beer2.event.append(event)
db.session.commit()
The values to be saved aren't strings, but for the sake of simplicity I replaced them. The values are there though and in the database there aren't any empty rows.
I don't know whether I set up the model wrong or whether it's an issue while committing. Any help would be appreciated.
I'm deeply sorry, I just found the problem. Obviously I forgot to add the items to the session. All that missed were db.session.add(event). I was trying to figure this out for at least 6 hours now but I just found it after I posted the problem to stackoverflow.
I am trying to wrap my head around SQLAlchemy in combination with Marshmallow. I had a Flask API that contains some Assets and Trading Pairs. I want bidirectional One-to-Many relationships between these models. I have the following code:
class Asset(db.Model):
__tablename__ = 'asset'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=True, nullable=False)
abbreviation = db.Column(db.String(20), unique=True, nullable=True)
trading_bases = relationship("TradingPair", back_populates="base_asset", foreign_keys="TradingPair.base_id")
trading_quotes = relationship("TradingPair", back_populates="quote_asset", foreign_keys="TradingPair.quote_id")
class TradingPair(db.Model):
__tablename__ = 'trading_pair'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=True, nullable=False)
# One to many (a pair can have only one base, but 1 asset can be the base of many pairs)
base_id = db.Column(db.Integer, db.ForeignKey("asset.id"), nullable=False)
base_asset = relationship("Asset", foreign_keys=[base_id], uselist=False, back_populates="trading_bases")
# One to many (same reasoning)
quote_id = db.Column(db.Integer, db.ForeignKey("asset.id"), nullable=False)
quote_asset = relationship("Asset", foreign_keys=[quote_id], uselist=False, back_populates="trading_quotes")
With the following resource for trading pair POST:
def post(self, name):
pair = TradingPair.query.filter_by(name=name).first()
if pair:
return {"Error": "This resource already exists"}, 409
data = request.get_json()
schema = TradingPairSchema()
try:
pair = schema.load(data, session=db.session)
if not pair.name == name:
return {"Error": f"{name} does not correspond to name in data"}
db.session.add(pair)
db.session.commit()
return {"Success":f"Added: {pair.name}"}
except ValidationError as e:
return {"Error": e.messages}, 400
except:
return {"Error":"Database error"}, 500
I expect SQLAlchemy to add new Assets that are POSTed as part of a new trading pair. However, if I want to post new pairs via the API using the following JSON:
{'name': 'DASHUSDT',
'base_asset': {
'name': 'Dash',
'abbreviation': 'DASH'},
'quote_asset': {
'name': 'Tether',
'abbreviation':
'USDT'}}
This works properly and the pair gets added to the DB as expected. The problem occurs when I try to add another pair that contains Dash or Tether. The pair is added again to the DB and my uniqueness constraint on the Asset table is violated. How can I ensure that a new instance is not created but the existing asset is used?
I ended up with checking whether the assets exist and adding them to the database if they do not yet exist. The code I used in the POST function of the trading pair is:
loaded = schema.load(data, session=db.session)
if not loaded.name == name:
return {"Error": f"{name} does not correspond to name in data"}
base = Asset.query.filter_by(abbreviation=loaded.base_asset.abbreviation).first()
if not base:
base = Asset(name=loaded.base_asset.name , abbreviation=loaded.base_asset.abbreviation)
db.session.add(base)
quote = Asset.query.filter_by(abbreviation=loaded.quote_asset.abbreviation).first()
if not quote:
quote = Asset(name=loaded.quote_asset.name, abbreviation=loaded.quote_asset.abbreviation)
db.session.add(quote)
pair = TradingPair(name=name, base_asset=base, quote_asset=quote)
db.session.add(pair)
db.session.commit()
This seems to work properly when the Asset already exist, but also does not crash when a new Asset is inserted via the POST of a trading pair. I could not find any documentation in either SQLAlchemy, Flask-SQLAlchemy or Marshmallow-SQLAlchemy on how this should be handled properly but for now, this works.
I want to allow users to Create Class and link their database from the front-end to add few Inputs like ( column definitions )
for example I want the users to pick
1- column name
2- type of column
3- primary key ( True or False )
4- character count
5- unique ( True or False )
i want pyton to create something like this
class Users(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
location = db.Column(db.String(25))
name = db.Column(db.String(80))
title = db.Column(db.String(25))
def __init__(self,email,password,active,confirmed_at,location,name,title):
#self.id = id
self.email = email
self.password = password
self.location = location
self.name = name
self.title = title
also i want python to allow user to link there database ( 1 for every session )
app.config['SQLALCHEMY_DATABASE_URI'] = '< user_input_goes_here >'
i can't find a title to what i'm looking for but i guess the code might be similar to the back end of the "adminer.cs50.net" because it can read the database of whatever input we
just googling and i'm not sure what i should be looking for
still its an idea i have no code yet
app.config['SQLALCHEMY_DATABASE_URI'] = '< user_input_goes_here >'
class Users(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
location = db.Column(db.String(25))
name = db.Column(db.String(80))
pos = db.Column(db.String(25))
def __init__(self,email,password,active,confirmed_at,location,name,pos,entryNo,userCode):
#self.id = id
self.email = email
self.password = password
self.location = location
self.name = name
self.pos = pos
I trying to learn how to code in Flask and am building a small portal that accepts inputs from the user (User could select among various check boxes). Based on the input I am trying to display the selected columns by means of an excel file. Given below what I have done thus far and I am not sure how to take this forward.
#app.route('/index', methods=['GET','POST'])
def user_input():
form = SampleForm()
if form.validate_on_submit():
Username = form.username_field.data
Age = form.age_field.data
output = user_input(Username,Age)
return render_template('index', form=form)
I have managed to build the above code by reading through various blogs and posts but this does nothing. Could anyone guide me on where am I going wrong with the above sample piece of code. Thanks
Class.py
class test(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100), nullable=False)
age = db.Column(db.String(100), nullable=False)
Python function:
def function(*field_names):
cursor = conn.cursor()
dwh_cursor.execute('select {} from enrolments'.format(', '.join(str(field) for field in field_names)))
print(field_names)
output_file = dwh_cursor.fetchall()
Does this help? Might need some tweaking to fit your needs.
#app.route('/index', methods=['GET','POST'])
def user_input():
form = SampleForm()
if form.validate_on_submit():
newform = User(
username = form.username_field.data,
age = form.age_field.data,
)
db.session.add(newform)
db.session.commit()
return redirect(url_for('user_input'))
return render_template('user_input', form = form)