Flask-SQLAlchemy Query Join relational tables

后端 未结 2 1915
栀梦
栀梦 2020-12-23 13:02

I am building an app using Flask & SQLAlchemy. I basically have 3 tables: users, friendships and bestFriends:

A user can have many friends but only one best frie

相关标签:
2条回答
  • 2020-12-23 13:05

    The error message is telling you that SQLAlchemy can't determine how to join the two tables users and friendships, because there is more than one foreign key linking them. You need to explicitly define the join condition.

    Try:

    userList = users.query\
        .join(friendships, users.id==friendships.user_id)\
        .add_columns(users.userId, users.name, users.email, friends.userId, friendId)\
        .filter(users.id == friendships.friend_id)\
        .filter(friendships.user_id == userID)\
        .paginate(page, 1, False)
    
    0 讨论(0)
  • 2020-12-23 13:22

    Ok looks like after getting some sleep and viewing Matthewh's suggestion I almost found the final solution:

    My model:

    from app import db
    from sqlalchemy.orm import relationship, backref
    from sqlalchemy import Table, Column, Integer, ForeignKey
    from sqlalchemy.ext.declarative import declarative_base
    
    class users(db.Model):
        __tablename__ = "Users"
    
        id = db.Column(db.Integer, primary_key=True)
        userName = db.Column(db.String, nullable=False)
        userEmail = db.Column(db.String, nullable=False)
        userPhone = db.Column(db.String, nullable=False)
        userPass = db.Column(db.String, nullable=False)
    
        def __init__(self, userName, userEmail, userPhone, userPass):
            self.userName = userName
            self.userEmail = userEmail
            self.userPhone = userPhone
            self.userPass = userPass
    
        def __repr__(self):
            return '{}-{}-{}-{}'.format(self.id, self.userName, self.userEmail, self.userPhone)
    
    
     class friendships(db.Model):
        __tablename__ = "Friendships"
    
        id = db.Column(db.Integer, primary_key=True)
        user_id = db.Column(db.Integer, db.ForeignKey('Users.id'), nullable=False)
        friend_id = db.Column(db.Integer, db.ForeignKey('Users.id'), nullable=False)
        userR = db.relationship('users', foreign_keys='friendships.user_id')
        friendR = db.relationship('users', foreign_keys='friendships.friend_id')
    
        def __init__(self, user_id, friend_id):
            self.user_id = user_id
            self.friend_id = friend_id
    
        def __repr__(self):
            return '{}-{}-{}-{}'.format(self.user_id, self.friend_id)
    
    
    class bestFriends(db.Model):
        __tablename__ = "BestFriends"
    
        id = db.Column(db.Integer, primary_key=True)
        user_id = db.Column(db.Integer, db.ForeignKey('Users.id'), nullable=False)
        best_friend_id = db.Column(db.Integer, db.ForeignKey('Users.id'), nullable=False)
        user = db.relationship('users', foreign_keys='bestFriends.user_id')
        best_friend = db.relationship('users', foreign_keys='bestFriends.best_friend_id')
    
        def __init__(self, user_id, best_friend_id):
            self.user_id = user_id
            self.best_friend_id = best_friend_id
    
        def __repr__(self):
            return '{}-{}-{}-{}'.format(self.user_id, self.best_friend_id)
    

    My app.py function(shows friends of user logged in):

    @app.route('/friendList<int:page>', methods=['GET', 'POST'])
    @app.route('/friends')
      def friendList(page=1):
      if not session.get('logged_in'):
         return render_template('login.html')
      else:
         userID = session['user_id']
         userList = users.query.join(friendships, users.id==friendships.user_id).add_columns(users.id, users.userName, users.userEmail, friendships.id, friendships.user_id, friendships.friend_id).filter(friendships.friend_id == userID).paginate(page, 1, False)
         return render_template('friends.html', userList=userList)
    

    And the Jinja side of 'friends.html':

    {% extends "layout.html" %}
    
    {% block body %}
        <div id="pagination">
            {% if userList.has_prev %}
                <a href="{{ url_for('friendList', page=userList.prev_num)}}">Back</a>
            {% endif %}
    
            {% if userList.has_next %}
                <a href="{{ url_for('friendList', page=userList.next_num)}}">Next</a>
            {% endif %}
        </div>
    
        <div style="clear:both;"></div>
    
        <div id="innerContent">
        {% if userList.items %}
            {% for friends in userList.items %}
                <div class="contentUsers">
                    {{ friends.userName }}
                </div>
                <br><br><br><br>
            {% endfor %}
            {% else %}
                <div>No friends</div>
            {% endif %}
        </div>
    {% endblock %}
    

    This gives me an object(friends in userList.items) like this:

    (2-Carlos-carlos@carlos.com-900102030, 2, u'Carlos', u'carlos@carlos.com', 2, 2, 1)
    

    I was expecting this: |users.id|users.userName|users.userEmail|users.userPhone|friendships.id|friendships.user_id(the friends)| friendships.friend_id(the logged in user)|

    So I have the following doubts/questions:

    I am not completely understanding the structure of the object resulting for the query:

    -repeated user id, name and email -what is the 'u' infront of second name and email

    I am not completely understanding the relations model structure:

    • why is the following NOT required in the 'users' class of the database model:

      #friendsR = db.relationship('friendships', backref='friendships.friend_id', primaryjoin='users.id==friendships.user_id', lazy='joined')
      

    IS my database model correctly defined regarding standarized relationship model as posted in this answer or should I improove some how??

    0 讨论(0)
提交回复
热议问题