I have the following database model:
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(20), unique=True, nullable=False)
password = db.Column(db.String(30), nullable=False)
email = db.Column(db.String(100), nullable=False, unique=True)
adverts = db.relationship('Advert', backref='autor', lazy=True)
messages_sent = db.relationship('Message',foreign_keys='Message.sender_id', backref='author', lazy='dynamic')
messages_received = db.relationship('Message',foreign_keys='Message.recipient_id', backref='recipient', lazy='dynamic')
telephone = db.Column(db.String(15))
def __repr__(self):
return f"User('{self.username}', '{self.email}'"
class Advert(db.Model):
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.DateTime, nullable=False, default = datetime.utcnow)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable = False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
category = db.Column(db.String(50), nullable=False)
price = db.Column(db.Integer)
city = db.Column(db.String(), nullable=False)
messages = db.relationship('Message', backref='messages', lazy=True)
def __repr__(self):
return f"Advert('{self.title}', '{self.date}', '{self.category}')"
class Message(db.Model):
id = db.Column(db.Integer, primary_key=True)
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))
title = db.Column(db.String(100), nullable=False)
body = db.Column(db.String(300), nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
ad_title = db.relationship('Advert', foreign_keys='Advert.title', backref='adtitle', lazy='dynamic')
def __repr__(self):
return f"Message('{self.body}')"
but the relationship between Message and Advert tables doesn't work. I want to do that the every Message have refer to Advert title. Anyone know the solution for this problem?
Related
I am trying to get the price value from my EVENTS class as an INT so that I can use it to make a booking by multiplying by the number of attendees for an event when I insert a new row in the booking table.
Tables in databse
class Event(db.Model):
__tablename__ = 'events'
id = db.Column(db.Integer, primary_key=True)
host = db.Column(db.String(80), nullable=False)
event_title = db.Column(db.String(80), nullable=False)
event_description = db.Column(db.String(80), nullable=False)
movie_name = db.Column(db.String(80), nullable=False)
movie_description = db.Column(db.String(80), nullable=False)
genre = db.Column(db.String(80), nullable=False)
movie_start_time = db.Column(db.Time(), nullable=False)
movie_end_time = db.Column(db.Time(), nullable=False)
classification = db.Column(db.String(80), nullable=False)
rating = db.Column(db.Integer(), nullable=False)
actors = db.Column(db.String(200), nullable=False)
directors = db.Column(db.String(200), nullable=False)
event_date = db.Column(db.Date(), nullable=False)
published_date = db.Column(db.Date(), nullable=False)
published_by = db.Column(db.String(80), nullable=False)
image = db.Column(db.String(60), nullable=False)
capacity = db.Column(db.Integer(), nullable=False)
address = db.Column(db.String(80), nullable=False)
status = db.Column(db.String(80), nullable=False)
price = db.Column(db.Integer(), nullable=False)
# ... Create the Comments db.relationship
# relation to call destination.comments and comment.destination
comments = db.relationship('Comment', backref='event')
class Booking(db.Model):
__tablename__ = 'bookings'
id = db.Column(db.Integer, primary_key=True, unique=True)
attendees = db.Column(db.Integer(), nullable=False)
total_price = db.Column(db.Integer(), nullable=False)
booked_at = db.Column(db.DateTime, default=datetime.now())
# foreign key
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
event_id = db.Column(db.Integer, db.ForeignKey('events.id'))
Code calling from Events table to get price and insert new row into Booking table
price = Event.query.with_entities(Event.price).filter_by(id = event)
user_name = User.query.with_entities(User.id).filter_by(name = current_user.name)
num_attendees = forms.attendees.data
print(num_attendees)
print(type(price))
booking = Booking(attendees=forms.attendees.data,
total_price= price * num_attendees,
user_id = user_name,
event_id = event)
#here the back-referencing works - comment.destination is set
# and the link is created
db.session.add(booking)
db.session.commit()
But I keep running into errors such as TypeError: unsupported operand type(s) for *: 'Row' and 'int'
Thank you
I am beginner trying to make a relational database in Flask project using SQLalchemy
This is the error that I am getting when I try to register a user:-
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Question->question, expression 'Answer' failed to locate a name ('Answer'). If this is a class name, consider adding this relationship() to the <class 'nothingness.models.Question'> class after both dependent classes have been defined.
DB relationships are:-
User (Many to Many) Table
User (1 to Many) Question
Question (1 to Many) Answer
Table (1 to Many) Question
Here are my codes
from datetime import datetime
from nothingness import db
members = db.Table(
"member",
db.Column("id", db.Integer, primary_key=True),
db.Column("table_id", db.Integer, db.ForeignKey("table.id")),
db.Column("user_id", db.Integer, db.ForeignKey("user.id")),
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(25), unique=True, nullable=False)
name = db.Column(db.String(25), nullable=False)
email = db.Column(db.String(), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default="default.jpg")
password = db.Column(db.String(60), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
member = db.relationship("Table", secondary=members, backref=db.backref("members", lazy=True))
prashna = db.relationship("Question", backref="user", lazy=True)
def __repr__(self):
return f"User('{self.name}', '{self.username}', '{self.email}', '{self.image_file}')db.Model"
class Table(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(25), nullable=False)
key = db.Column(db.String(5), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
question = db.relationship("Question", backref="questions", lazy=True)
def __repr__(self):
return f"Table('{self.id}', '{self.name}', '{self.key}', {self.created_at})"
class Question(db.Model):
id = db.Column(db.Integer, primary_key=True)
question = db.Column(db.String(255), nullable=False)
asked_by = db.Column(db.Integer, db.ForeignKey("user.id"))
asked_to = db.Column(db.Integer, nullable=False)
answer = db.relationship("Answer", backref="question", lazy=True)
table = db.Column(db.Integer, db.ForeignKey("table.id"))
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
class Answer:
id = db.Column(db.Integer, primary_key=True)
points = db.Column(db.Integer)
answer = db.Column(db.String(255), nullable=False)
answered_by = db.Column(db.Integer, nullable=False)
table_id = db.Column(db.Integer, nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
question = db.Column(db.Integer, db.ForeignKey("question.id"))
def __repr__(self):
return f"Answer('{self.points}', '{self.answer}', '{self.created_at}')"
This error occurred because I forgot to subclass Answer with db.Model
I have some models that i'd like to migrate, 2 of them are:
FamilyMember.py
class FamilyMember(db.Model):
__tablename__ = 'family_members'
id = db.Column(db.Integer, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey('users.id'))
name = db.Column(db.String(120), index=True)
email = db.Column(db.String(120), index=True, unique=True)
password = db.Column(db.String(128), nullable=False)
notification = db.Column(db.Boolean, default=True)
auto_ml = db.Column(db.Boolean, default=True)
photo = db.Column(db.String(128), nullable=True)
created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
updated_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now(), onupdate=db.func.now())
notifications = db.relationship('Notification', backref='family_members', lazy='dynamic')
And Notification.py
class Notification(db.Model):
__tablename__ = 'notifications'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
fm_id = db.Column(db.Integer, db.ForeignKey('family_members.id'))
text = db.Column(db.String(255))
read = db.Column(db.Boolean, default=False)
type = db.Column(db.Integer)
created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
updated_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now(), onupdate=db.func.now())
Regarding to this post, i have to explicitly state table name with __tablename__ = 'tablename', i've done that but it didn't work the way it supposed to and still got the error sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'notifications.fm_id' could not find table 'family_members' with which to generate a foreign key to target column 'id'. What should i do?
You can use back_populates instead of backref in db.relationship()
class Notification(db.Model):
__tablename__ = 'notifications'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
fm_id = db.Column(db.Integer, db.ForeignKey('family_members.id'))
text = db.Column(db.String(255))
read = db.Column(db.Boolean, default=False)
type = db.Column(db.Integer)
created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
updated_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now(), onupdate=db.func.now())
family_members = db.relationship("FamilyMember", back_populates="notifications")
class FamilyMember(db.Model):
__tablename__ = 'family_members'
id = db.Column(db.Integer, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey('users.id'))
name = db.Column(db.String(120), index=True)
email = db.Column(db.String(120), index=True, unique=True)
password = db.Column(db.String(128), nullable=False)
notification = db.Column(db.Boolean, default=True)
auto_ml = db.Column(db.Boolean, default=True)
photo = db.Column(db.String(128), nullable=True)
created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
updated_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now(), onupdate=db.func.now())
notifications = db.relationship("Notification", back_populates="family_member")
I have three models : user, houses and a post.
I am trying to assign a post to one author and mutliple recipients, but I do not know how to do it.
I reckon it may have to do with relationships between tables...
These are my models
lettings = db.Table('lettings',
db.Column('tenant_id', db.Integer, db.ForeignKey('user.id')),
db.Column('property_id', db.Integer, db.ForeignKey('house.id'))
)
class User(UserMixin, db.Model):
__tablename__ = 'user'
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)
password_hash = db.Column(db.String(128))
lettings = db.relationship("Houses",secondary=lettings,lazy="dynamic", backref=db.backref("tenants",lazy="dynamic"))
posts_sent = db.relationship('Post',
foreign_keys='Post.sender_id',
backref='author', lazy='dynamic')
posts_received = db.relationship('Post',
foreign_keys='Post.recipient_id',
backref='recipient', lazy='dynamic')
last_post_read_time = db.Column(db.DateTime)
def haslived(self,house):
if not self.isliving(house):
self.lettings.append(house)
def unlived(self, house):
if self.isliving(house):
self.lettings.remove(house)
def isliving(self, house):
return self.lettings.filter_by(id=house.id).first()
class Post(db.Model):
__tablename__ = 'post'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(32))
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))
house_id = db.Column(db.Integer, db.ForeignKey('house.id'))
__searchable__= ['body']
def __repr__(self):
return '<Post {}>'.format(self.body)
class Houses(db.Model):
__tablename__ = 'house'
id = db.Column(db.Integer, primary_key=True,index=True)
address = db.Column(db.String(120))
postcode = db.Column(db.String(120),index=True)
licence_holder = db.Column(db.String(140),index=True)
__searchable__=['address']
posts = db.relationship('Post', backref='letting', lazy='dynamic')
def __repr__(self):
return '<House {}>'.format(self.address)
And this is my routes code snippet:
#bp.route('/house/<address>/ask',methods=['GET', 'POST'])
#login_required
def ask(address):
house = Houses.query.filter_by(address=address).first_or_404()
form = PostForm()
if form.submit.data and form.validate_on_submit():
post = Post(body=form.body.data,title=form.title.data,author=current_user,letting=house,recipient={I do not know what to write here})
db.session.add(post)
db.session.commit()
flash('Your post is now live!')
return redirect(url_for('main.house', address=house.address))
return render_template('ask.html', title='Ask a question about {}'.format(house.address),form=form,house=house)
My objective is to create a post object which will have only one sender but multiple recipients.
Thank you for your help.
Yes, as somebody above correctly pointed out, this can be done using many-to-many relationship from SQLalchemy.
I got the answer myself, that's how i modified the code:
My models:
lettings = db.Table('lettings',
db.Column('tenant_id', db.Integer, db.ForeignKey('user.id')),
db.Column('property_id', db.Integer, db.ForeignKey('house.id'))
)
class User(UserMixin, db.Model):
__tablename__ = 'user'
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)
password_hash = db.Column(db.String(128))
reviews = db.relationship('Review', backref='author', lazy='dynamic')
checklists = db.relationship('Checklist', backref='author', lazy='dynamic')
about_me = db.Column(db.String(140))
lettings = db.relationship("Houses",secondary=lettings,lazy="dynamic", backref=db.backref("tenants",lazy="dynamic"))
posts_sent = db.relationship('Post',
foreign_keys='Post.sender_id',
backref='author', lazy='dynamic')
last_post_read_time = db.Column(db.DateTime)
def new_posts(self):
last_read_time = self.last_post_read_time or datetime(1900, 1, 1)
return Post.query.filter_by(recipients=self).filter(
Post.timestamp > last_read_time).count()
def haslived(self,house):
if not self.isliving(house):
self.lettings.append(house)
def unlived(self, house):
if self.isliving(house):
self.lettings.remove(house)
def isliving(self, house):
return self.lettings.filter_by(id=house.id).first()
def __repr__(self):
return '<User {}>'.format(self.username)
recipients = db.Table('recipients',
db.Column('recipient_id', db.Integer, db.ForeignKey('user.id')),
db.Column('post_id', db.Integer, db.ForeignKey('post.id'))
)
class Post(db.Model):
__tablename__ = 'post'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(32))
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
recipients = db.relationship("User",secondary=recipients,lazy="dynamic", backref=db.backref("posts_received",lazy="dynamic"))
house_id = db.Column(db.Integer, db.ForeignKey('house.id'))
__searchable__= ['body']
def __repr__(self):
return '<Post {}>'.format(self.body)
def add_recipient(self, recipient):
self.recipients.append(recipient)
class Houses(db.Model):
__tablename__ = 'house'
id = db.Column(db.Integer, primary_key=True,index=True)
address = db.Column(db.String(120))
postcode = db.Column(db.String(120),index=True)
licence_holder = db.Column(db.String(140),index=True)
__searchable__=['address']
posts = db.relationship('Post', backref='letting', lazy='dynamic')
reviews = db.relationship('Review', backref='house', lazy='dynamic')
checklists = db.relationship('Checklist', backref='house', lazy='dynamic')
latitude=db.Column(db.Float(precision=32,decimal_return_scale=None),index=True)
longitude=db.Column(db.Float(precision=30,decimal_return_scale=None),index=True)
def __repr__(self):
return '<House {}>'.format(self.address)
And you add all the recipients to a post once its uploaded by a different user using list comprehension:
Post(body=form.body.data,title=form.title.data,author=current_user,letting=house)
[post.add_recipient(recipient) for recipient in house.tenants.all()]
db.session.add(post)
db.session.commit()
In rendering an html template, the minutes_id is not being passed through correctly. It's throwing the error: "AttributeError: 'InstrumentedList' object has no attribute 'get'". I'm not sure how to fix this.
This is the line of code tripping me up.
minutes = club.minutes.get(minutes_id) #GET THE Minutes for specific DAY
routes.py:
#clubs.route("/view_minutes/<int:user_id>/<int:club_id>", methods=['GET', 'POST'])
#login_required
def view_minutes(user_id, club_id):
club = Club.query.get_or_404(club_id)
user = User.query.get_or_404(user_id)
minutes = club.minutes
#if click "export" -->
#return render_pdf(url_for('minutes_pdf', user_id=user_id, club_id=club_id))
return render_template('view_minutes.html', title='View', user=user, club=club, minutes=minutes)
#clubs.route("/minutes_pdf/<int:user_id>/<int:club_id>/<int:minutes_id>.pdf", methods=['GET', 'POST'])
#login_required
def minutes_pdf(user_id, club_id, minutes_id):
club = Club.query.get_or_404(club_id)
user = User.query.get_or_404(user_id)
minutes = club.minutes.get(minutes_id) #GET THE Minutes for specific DAY
return render_template('view_minutes_pdf.html', club=club, minutes=minutes)
models.py
user_club_assoc_table = db.Table('user_club_assoc_table',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('club_id', db.Integer, db.ForeignKey('club.id')))
roles = db.relationship('Role', secondary='user_roles',
backref=db.backref('users', lazy='dynamic'))
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(15), nullable=False)
lastname = db.Column(db.String(15), nullable=False)
email = db.Column(db.String(60), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
role = db.Column(db.Integer(), nullable=False, default=ROLES['student'])
clubs = db.relationship('Club', secondary=user_club_assoc_table)
def __repr__(self):
return f'{self.firstname} {self.lastname}' #return f'User(firstname={self.firstname!r}, lastname={self.lastname!r})'
class Club(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
members = db.relationship('User', secondary=user_club_assoc_table)
minutes = db.relationship('Minutes', backref='club')
def __repr__(self):
return f'{self.name}'#Club(name={self.name!r})
class Minutes(db.Model):
id = db.Column(db.Integer, primary_key=True)
club_id = db.Column(db.Integer, db.ForeignKey('club.id'))
date = db.Column(db.Date, nullable=False) #0000-00-00
time = db.Column(db.Time) #00:00:00
location = db.Column(db.String(100), nullable=False)
attendance = db.relationship('Attendance', backref='minutes', lazy=True) #check code
purchase = db.Column(db.Text)
purchasemotion = db.Column(db.Text)
fundraiser = db.Column(db.Text)
fundmotion = db.Column(db.Text)
minute = db.Column(db.Text, nullable=False) #notes
def __repr__(self):
return f'{self.club_id} {self.date}'
class Attendance(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
student_name = db.Column(db.String(35), nullable=False)
present = db.Column(db.Boolean, default=False) #set correctly
minutes_id = db.Column(db.Integer, db.ForeignKey('minutes.id'))
In the url you are already capturing minute_id why don't you query directly
Minutes.query.get_or_404(minute_id)