首页 > 解决方案 > Flask:如何根据聊天室添加聊天记录?

问题描述

我正在尝试在我的烧瓶应用程序中实现一项功能,用户可以在其中创建或加入房间并相互聊天。我已经建立了用户可以聊天、创建和加入房间的部分,但我还想根据他们所在的房间添加聊天历史记录,这样当新用户加入或离开和加入时,他们可以看到所有以前的特定消息到他们所在的聊天室。消息在发送时也会保存。我现在遇到的问题是我需要显示消息并将它们保留在特定于房间的位置。我知道这需要 AJAX 和 Javascript,但我对它们都是新手。如果有人可以帮助我理解并提供以下代码来解决此问题,将不胜感激。代码如下,提前致谢!

主文件

    from flask import Flask, request, session, render_template, redirect, url_for, flash, get_flashed_messages, jsonify
    from flask.globals import current_app
    from flask_login import LoginManager, login_user, login_required, logout_user, current_user, UserMixin, AnonymousUserMixin
    from datetime import timedelta, datetime
    from werkzeug.security import generate_password_hash, check_password_hash
    import sqlite3
    from os import error, path
    from flask_sqlalchemy import SQLAlchemy
    import random
    from flask_socketio import SocketIO, join_room, leave_room, emit
    from flask_session import Session

    app = Flask(__name__)
    DB_NAME = "spark.db"
    app.config["SECRET_KEY"] = "1986319249872139865432"
    app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{DB_NAME}"
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
    app.config['SESSION_TYPE'] = 'filesystem'


    Session(app)

    socketio = SocketIO(app, manage_session=False)

    db = SQLAlchemy(app)
    db.init_app(app)

    def create_database(app):
        if not path.exists(DB_NAME):
            db.create_all(app=app)
            print("Created Database!")

    class Tutor(db.Model, UserMixin):
        id = db.Column(db.Integer, primary_key=True)
        user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        tremail = db.Column(db.String(10000))
        trusername = db.Column(db.String(1200))
        subjects = db.Column(db.String(1200))
        session_length = db.Column(db.String(1200))

    class Content(db.Model, UserMixin):
        id = db.Column(db.Integer, primary_key=True)
        room_id = db.Column(db.Integer)
        message = db.Column(db.String(5000))


    class User(db.Model, UserMixin):
        id = db.Column(db.Integer, primary_key=True)
        email = db.Column(db.String(150), unique=True)
        username = db.Column(db.String(150), unique=True)
        password = db.Column(db.String(150))
        tutors = db.relationship('Tutor')


    create_database(app)

    login_manager = LoginManager()
    login_manager.login_view = 'login'
    login_manager.init_app(app)
    @login_manager.user_loader
    def load_user(id):
        return User.query.get(int(id))


    @app.route("/")
    @login_required
    def home():
        return render_template("index.html")

    @app.route("/login", methods=["GET", 'POST'])
    def login():
        if request.method == "POST":
            email = request.form.get('email')
            password = request.form.get('password')

            user = User.query.filter_by(email=email).first()
            if user:
                if check_password_hash(user.password, password):
                    flash('Login successful!', category="success")
                    login_user(user, remember=True)
                    return redirect(url_for("home"))
                else:
                    flash('Incorrect password! Please try again.', category="error")
            else:
                flash("Account does not exist. Please register to continue.", category="error")


        return render_template("login.html", user=current_user)

    @app.route("/register", methods=["GET", "POST"])
    def register():
        if request.method == 'POST':
            email = request.form.get('email')
            username = request.form.get('username')
            password1 = request.form.get('password1')
            password2 = request.form.get('password2')

            user = User.query.filter_by(email=email).first()
            if user:
                flash("Email already exists.", category="error")
            elif len(email) < 4:
                flash("Email must be greater than 3 characters.", category="error")
            elif len(username) < 2:
                flash("Username must be greater than 1 character.", category="error")
            elif password1 != password2:
                flash("Passwords do not match! Please try again.", category="error")
            elif len(password1) < 8:
                flash("Password must be greater than 7 characters.", category="error")
            else:
                new_user = User(email=email, username=username, password=generate_password_hash(password1, method='sha256'))
                db.session.add(new_user)
                db.session.commit()
                login_user(new_user, remember=True)
                flash("Account successfully created!", category="success")

                return redirect(url_for('home'))

        return render_template("register.html", user=current_user)

    @app.route("/logout")
    @login_required
    def logout():
        logout_user()
        flash("Logged out succcessfully!", category="success")
        return redirect(url_for('login'))

    @app.route("/selection")
    @login_required
    def selection():
        return render_template("selection.html")

    @app.route("/tutorform", methods=['GET', 'POST'])
    @login_required
    def tutorform():
        if request.method == 'POST':
            email = request.form.get('email')
            tremail = request.form.get('tremail')
            trusername = request.form.get('trusername')
            subjects = request.form.get('subjects')
            session_length = request.form.get('session_length')

            new_tutor = Tutor(user_id=current_user.id, tremail=tremail, trusername=trusername, subjects=subjects, session_length=session_length)
            db.session.add(new_tutor)
            db.session.commit()
            flash('Entry has been saved!', category='success')
            return redirect(url_for("display"))

        return render_template("tutorform.html", user=current_user)

    @app.route("/tutoreeform", methods=['GET', 'POST'])
    @login_required
    def tutoreeform():
        if request.method == 'POST':
            flash("Tutoree Entry Successful!", category='success')
            return redirect(url_for("display"))

        return render_template("tutoreeform.html")

    @app.route("/display")
    @login_required
    def display():
        users = Tutor.query.all()

        messages = Content.query.all()

        return render_template("display.html", users=users, messages=messages)

    @login_required
    @app.route('/chat', methods=['GET', 'POST'])
    def chat():
        if(request.method=='POST'):
            username = current_user.username
            room = request.form['room']
            #Store the data in session
            session['username'] = username
            session['room'] = room
            return render_template('chat.html', session = session)
        else:
            if(current_user.username is not None):
                return render_template('chat.html', session = session)
            else:
                return redirect(url_for('chatselection'))

    class Anonymous(AnonymousUserMixin):
    def __init__(self):
        self.username = 'Guest'

    @socketio.on('join', namespace='/chat')
    @login_required
    def join(message):
        room = session.get('room')
        join_room(room)
        emit('status', {'msg': current_user.username + ' has entered the room.'}, room=room)


    @socketio.on('text', namespace='/chat')
    @login_required
    def text(message):
        room = session.get('room')
        sent_message = message['msg']
        emit('message', {'msg': session.get('username') + ' : ' + sent_message}, room=room)
        messages = Content(room_id=room, message=sent_message)
        db.session.add(messages)
        db.session.commit()


    @socketio.on('left', namespace='/chat')
    @login_required
    def left(message):
        room = session.get('room')
        leave_room(room)
        session.clear()
        emit('status', {'msg': current_user.username + ' has left the room.'}, room=room)

    @app.route("/chatselection", methods=['GET', 'POST'])
    def chatselection():
        return render_template("chatselection.html")


    if __name__ == '__main__':
        db.create_all()
        socketio.run(app, host="192.168.1.176", port=5000, debug=True)

base.html

    <!DOCTYPE html>
    <html>
        <head>
            <title >{% block title %}{% endblock %}</title>
            <link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='style.css') }}">
            <link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='bootstrap.min.css') }}">
            <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

            <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>

    <!-- Bootstrap core JavaScript -->
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

    <!-- Plugin JavaScript -->
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js"></script>
            <script src="https://cdn.jsdelivr.net/npm/startbootstrap-stylish-portfolio@5.0.9/js/stylish-portfolio.min.js"></script>

            <script type="text/javascript" src="//code.jquery.com/jquery-1.4.2.min.js"></script>
            <script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
            <script type="text/javascript" charset="utf-8">
                var socket;
                $(document).ready(function(){
                    socket = io.connect('http://' + document.domain + ':' + location.port + '/get_messages/<room_id>');
                    socket.on('connect', function() {
                        socket.emit('join', {});
                    });
                    socket.on('status', function(data) {
                        $('#chat').val($('#chat').val() + '<' + data.msg + '>\n');
                        $('#chat').scrollTop($('#chat')[0].scrollHeight);
                    });
                    socket.on('message', function(data) {
                        $('#chat').val($('#chat').val() + data.msg + '\n');
                        $('#chat').scrollTop($('#chat')[0].scrollHeight);
                    });
                    $('#send').click(function(e) {
                            text = $('#text').val();
                            $('#text').val('');
                            socket.emit('text', {msg: text});
                    });
                });
                function leave_room() {
                    socket.emit('left', {}, function() {
                        socket.disconnect();
                        // go back to the login page
                        window.location.href = "{{ url_for('display') }}";
                    });
                }
            </script>

        </head>
        <body style="background-image: url(https://i.pinimg.com/originals/55/74/54/557454f9d762c6b6c9efdaec66b4dbb9.jpg)">
            <nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #549bf773;">
                <a class="navbar-brand" href="/">
                    <img src="{{url_for('static', filename='logo.jpg')}}" alt="" width="40">
                </a>
                <a class="navbar-brand" href="/" style="color: rgb(22, 9, 3);"><i><b style="font-family: fantasy; font-size: larger;">SparkWIT</b></i></a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
                </button>

                {% if current_user.is_authenticated %}
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav mr-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="/" style="color: rgb(37, 20, 13);"><b><i>Home</i></b> <span class="sr-only">(current)</span></a>
                    </li>
                    <li class="nav-item active">
                        <a class="nav-link" href="/selection" style="color: rgb(37, 20, 13);"><b><i>Selection</i></b> <span class="sr-only">(current)</span></a>
                    </li>
                    </ul>
                    <a class="nav-link" href="/logout"><button type="button" class="btn btn-outline-danger" style="color: rgb(0, 0, 0);"><b>Logout</b></button></a>
                {% else %}

                    <a class="nav-link" href="/login"><button type="button" class="btn btn-outline-light"><b>Login</b></button></a>
                    <a class="nav-link" href="/register"><button type="button" class="btn btn-outline-warning"><b>Register</b></button></a>
                {% endif %}
                </div>
            </nav>

                    {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                {% if category == "error" %}
                <div class="alert alert-danger alter-dismissable fade show" role="alert">
                    {{ message }}
                    <button type="button" class="close" data-dismiss="alert">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                {% endif %}
                {% if category == "success" %}
                <div class="alert alert-success alter-dismissable fade show" role="alert">
                    {{ message }}
                    <button type="button" class="close" data-dismiss="alert">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                {% endif %}
                {% endfor %}
            {% endif %}
            {% endwith %}

            <div class="container">
                {% block content %}{% endblock %}
            </div>
            <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
            <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
        </body>
    </html>

聊天.html

{% extends "base.html" %}

{% block title %}SparkWIT | | Chat{% endblock %}

{% block content %}
    <div class="chatwindow">
        <center><h2 style="color: beige;">SparkWIT Babbles!</h2></center>
        <center><h3 style="color: beige;">Room : {{session['room']}}</h3></center><br>
        <center><textarea id="chat" cols="90" rows="12" placeholder="No messages yet. Start one..."></textarea><br /><br /></center>
        <div>
      <center><div class="buttonIn">
        <input type="text" id="text" name="text" size="75" placeholder="Enter your message here" />
        <button type="button" id="send" class="btn btn-success">SEND</button>
        <br>
        <br>
      </div></center>
      <center><button type="button" class="btn btn-danger" onclick=leave_room()>Leave this Chat</button></center>
    </div>
{% endblock %}

聊天选择.html

{% extends "base.html" %}
{% block title %}SparkWIT | | Chat Selection{% endblock %}

{% block content %}

<center><h1 class="h2 mb-3 font-weight-normal" style="color: beige;">Choose or Join a room!</h1><br><br></center>
<br>
<hr>
  <form class="form-signin" action="{{url_for('chat')}}" method="POST">
    <input type="number" id="room" name="room" class="form-control" placeholder="Room Code (Please enter a number)" required><br>
    <button class="btn btn-lg btn-dark btn-block" value="submit">Join Room</button>
  </form>
<br>
<br>
  <form class="form-signin" action="{{url_for('chat')}}" method="POST">
    <input type="number" id="room" name="room" class="form-control" placeholder="Room Code (Please enter a number)" required><br>
    <button class="btn btn-lg btn-secondary btn-block" value="submit">Create Room</button>
  </form>
<br>


{% endblock %}

标签: javascriptpythonhtmlajax

解决方案


推荐阅读