Flask:如何根据烧瓶中的聊天室添加聊天记录? [英] Flask: How to add chat history depending on the chat room in flask?

查看:80
本文介绍了Flask:如何根据烧瓶中的聊天室添加聊天记录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的烧瓶应用程序中实现一项功能,以便用户可以创建或加入房间并彼此聊天.我已经建立了用户可以聊天,创建和加入聊天室的部分,但是我还想根据他们所在的聊天室添加聊天记录,以便当新用户加入或离开并加入时,他们可以看到所有以前的特定消息.到他们所在的聊天室.我从创建一个类来存储消息开始.然后,我只是尝试在每次发送新消息时保存这些消息.出于某种原因,我不断收到错误消息.如果有人可以帮助我解决此问题并帮助我添加聊天记录,将不胜感激.代码和错误在下面.

main.py

从flask导入

 烧瓶,请求,会话,render_template,重定向,url_for,flash,get_flashed_messages,jsonify从flask.globals导入current_app从flask_login导入LoginManager,login_user,login_required,logout_user,current_user,UserMixin,AnonymousUserMixin从datetime导入timedelta,datetime从werkzeug.security导入generate_password_hash,check_password_hash导入sqlite3从操作系统导入错误,路径从flask_sqlalchemy导入SQLAlchemy随机导入从flask_socketio导入SocketIO,join_room,leave_room,发出从flask_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"] = Falseapp.config ['SESSION_TYPE'] ='文件系统'会话(应用)socketio = SocketIO(应用程序,manage_session = False)db = SQLAlchemy(应用程序)db.init_app(app)def create_database(app):如果不是path.exists(DB_NAME):db.create_all(app = app)打印(创建的数据库!")类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))subject = db.Column(db.String(1200))session_length = db.Column(db.String(1200))Messages类(db.Model,UserMixin):id = db.Column(db.Integer,primary_key = True)room_id = db.Column(db.String(1200),unique = True,nullable = False)内容= db.Column(db.String(10000))类User(db.Model,UserMixin):id = db.Column(db.Integer,primary_key = True)email = db.Column(db.String(150),unique = True)用户名= db.Column(db.String(150),unique = True)密码= db.Column(db.String(150))导师= db.relationship('Tutor')create_database(app)login_manager = LoginManager()login_manager.login_view ='登录'login_manager.init_app(app)@ login_manager.user_loaderdef load_user(id):返回User.query.get(int(id))@ app.route("/")@需要登录def home():返回render_template("index.html")@ app.route("/login",方法= ["GET","POST"])def login():如果request.method =="POST":电子邮件= request.form.get('电子邮件')密码= request.form.get('密码')用户= User.query.filter_by(email = email).first()如果用户:如果check_password_hash(user.password,password):flash(登录成功!",类别=成功")login_user(用户,记住= True)返回重定向(url_for("home"))别的:flash(密码错误!请重试.",类别=错误")别的:flash(帐户不存在.请注册以继续.",类别=错误")返回render_template("login.html",user = current_user)@ app.route("/register",methods = ["GET","POST"])def register():如果request.method =='POST':电子邮件= request.form.get('电子邮件')用户名= request.form.get('用户名')密码1 = request.form.get('password1')password2 = request.form.get('password2')用户= User.query.filter_by(email = email).first()如果用户:flash(电子邮件已经存在.",类别=错误")Elif len(电子邮件)<4:flash(电子邮件必须大于3个字符.",类别=错误")elif len(用户名)<2:flash(用户名必须大于1个字符.",类别=错误")elif password1!= password2:flash(密码不匹配!请重试.",类别=错误")Elif len(密码1)<8:flash(密码必须大于7个字符.",类别=错误")别的:new_user =用户(电子邮件=电子邮件,用户名=用户名,密码= generate_password_hash(密码1,方法='sha256'))db.session.add(new_user)db.session.commit()login_user(新用户,记住= True)flash(帐户创建成功!",类别=成功")返回重定向(url_for('home'))返回render_template("register.html",user = current_user)@ app.route("/登出")@需要登录def logout():logout_user()flash(成功注销!",类别=成功")返回重定向(url_for('login'))@ app.route("/selection")@需要登录def selection():返回render_template("selection.html")@ app.route("/tutorform",方法= ['GET','POST'])@需要登录def tutorform():如果request.method =='POST':电子邮件= request.form.get('电子邮件')tremail = request.form.get('tremail')trusername = request.form.get('trusername')主题= request.form.get('subjects')session_length = request.form.get('session_length')new_tutor =导师(user_id = current_user.id,tremail = tremail,trusername = trusername,主题=主题,session_length = session_length)db.session.add(new_tutor)db.session.commit()flash('条目已保存!',category ='成功')返回重定向(url_for("display")))return render_template("tutorform.html",user = current_user)@ app.route("/tutoreeform",方法= ['GET','POST'])@需要登录def tutoreeform():如果request.method =='POST':flash("Tutoree进入成功!",category =成功")返回重定向(url_for("display")))返回render_template("tutoreeform.html")@ app.route("/display")@需要登录def display():用户= Tutor.query.all()返回render_template("display.html",users = users)@需要登录@ app.route('/chat',methods = ['GET','POST'])def chat():if(request.method =='POST'):用户名= current_user.username房间= request.form ['房间']#将数据存储在会话中session ['用户名'] =用户名会话['房间'] =房间返回render_template('chat.html',会话=会话)别的:如果(current_user.username不为None):返回render_template('chat.html',session = session)别的:返回重定向(url_for('聊天选择'))类Anonymous(AnonymousUserMixin):def __init __():self.username ='访客'@ socketio.on('join',namespace ='/chat')@需要登录def join(消息):房间= session.get('房间')join_room(房间)发出('状态',{'msg':current_user.username +'已进入房间.'},room = room)@ socketio.on('文本',名称空间='/聊天')@需要登录def文字(消息):房间= session.get('房间')消息=消息(room_id =房间,内容=消息)db.session.add(消息)db.session.commit()发出('message',{'msg':session.get('username')+':'+ message ['msg']},room = room)@ socketio.on('left',namespace ='/chat')@需要登录def左(消息):房间= session.get('房间')离开房间session.clear()发出('状态',{'msg':current_user.username +'已离开房间.'},room = room)@ app.route("/chatselection",方法= ['GET','POST'])def chatselection():返回render_template("chatselection.html")如果__name__ =='__main__':db.create_all()socketio.run(app,debug = True) 

chat.html

  {%扩展了"base.html"%}{%标题%} SparkWIT ||聊天{%endblock%}{%封锁内容%}< div class ="chatwindow">< center>< h2 style ="颜色:米色;" SparkWIT Ba呀!/h2</center>< center>< h3 style ="颜色:米色;"房间:{{session ['room']}}</h3</center< br>< center>< textarea id =聊天"cols ="90".行="12"placeholder ="尚无消息.开始一个..."</textarea< br/>< br/></center>< div>< center>< div class ="buttonIn"><输入类型=文本";id ="text"名称=文本"尺寸="75"placeholder =在这里输入您的消息"/>< button type =按钮"id =发送"class ="btn btn-success"> SEND</button>< br>< br></div></center>< center><按钮类型=按钮"class ="btn btn-danger";onclick = leave_room()>离开此聊天室</button></center></div>{%endblock%} 

chatselection.html

  {%扩展了"base.html"%}{%标题%} SparkWIT ||聊天选择{%endblock%}{%封锁内容%}< center>< h1 class ="h2 mb-3字体重量正常"样式=颜色:米色;" SparkWIT泡泡/h1 br</center>< br>< hr>< form class ="form-signin"action =" {{url_for('chat')}}'"method ="POST"><输入类型=文本";id =房间"名称=房间"class ="form-control"占位符=房间代码"必需< br>< button class ="btn btn-lg btn-primary btn-block";值=提交">创建/加入房间</button></form>< br>{%endblock%} 

base.html

 <!DOCTYPE html>< html>< head><标题> {%块标题%} {%最终块%}</title>< link rel =样式表"type ="text/css";href =" {{url_for('static',filename ='style.css')}}'>< link rel =样式表"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"完整性="sha384-ggOyR0iXCbMQv3Xipma34MD + dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"crossorigin =匿名"< script src ="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js"完整性="sha384-JEW9xMcG8R + pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf"crossorigin =匿名"</script>< ;!-Bootstrap核心JavaScript->< script src =" https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"</script><!-插件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 ="文本/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"完整性="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh"crossorigin =匿名"</script>< script type ="文本/javascript"charset ="utf-8">var socket;$(document).ready(function(){socket = io.connect('http://'+ document.domain +':'+ location.port +'/chat');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});});});函数leave_room(){socket.emit('left',{},function(){socket.disconnect();//返回登录页面window.location.href ="{{url_for('display')}}'";});}</script></head>< body style =" background-image:url(https://media.istockphoto.com/photos/abstract-glittering-dna-helix-with-depth-of-field-over-dark-space-picture-id1201193016?k = 6& m = 1201193016& s = 612x612& w = 0& h = _H80RaLa4OYIiT136j_cFgm-YRHAiV4wmaSkSKAMFbQ =)< 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 ="宽度="40"</a>< a class ="navbar-brand"href ="/"样式=颜色:rgb(22,9,3);"< i>< b样式="font-family:幻想;字体大小:更大;" SparkWIT</b>/i</a>< button class ="navbar-toggler"type ="button"data-toggle =收合"data-target =#navbarSupportedContent"aria-controls ="navbarSupportedContent";aria-expanded =假"aria-label =切换导航"< span class ="navbar-toggler-icon"</span></button>{%,如果current_user.is_authenticated%}< div class ="collapse navbar-collapse";id ="navbarSupportedContent"< ul class ="navbar-nav mr-auto">< li class =活动的nav-item">< a class ="nav-link";href ="/"样式=颜色:rgb(37、20、13);" b"i i Home/i i/b".< span class =仅sr">(当前)/span</a></li>< li class =活动的nav-item">< a class ="nav-link";href ="/selection"样式=颜色:rgb(37、20、13);" b"i"选择"/i"/b.< span class =仅sr">(当前)/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>登出< b</button>/a;{% 别的 %}< a class ="nav-link";href ="/login">< button type ="button"class ="btn btn-outline-light"< b>登录< b>/button</a>< a class ="nav-link";href ="/register">< button type ="button"class ="btn btn-outline-warning"< b>寄存器</b>/按钮</a>.{% 万一 %}</div></nav>{包含邮件的百分比= get_flashed_messages(with_categories = true)%}{%,如果消息%}{类别的%,消息中的消息%}{%,如果类别==错误";%}< div class =警告警报-危险可改变-可关闭的淡入淡出".角色=警报"{{ 信息 }}< button type =按钮"class ="close"data-dismiss =警报">.< span aria-hidden ="true"& times;</span></button></div>{% 万一 %}{%,如果类别==成功";%}< div class =警报成功成功的可改变的淡入淡出显示";角色=警报"{{ 信息 }}< button type =按钮"class ="close"data-dismiss =警报">.< span aria-hidden ="true"& times;</span></button></div>{% 万一 %}{%endfor%}{% 万一 %}{%以%结尾}< div class =容器">{%块内容%} {%最终块%}</div>< script src =" https://code.jquery.com/jquery-3.3.1.slim.min.js"完整性="sha384-q8i/X + 965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH + 8abtTE1Pi6jizo"crossorigin =匿名"</script>< script src ="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"完整性="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"crossorigin =匿名"</script>< script src =" https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"完整性="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM + B07jRM"crossorigin =匿名"</script></body></html> 

这是我遇到的错误.

线程Thread-32中的

 异常:追溯(最近一次通话):_execute_context中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ base.py",行1276self.dialect.do_execute(do_execute中的文件``C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ default.py'',第593行cursor.execute(语句,参数)sqlite3.InterfaceError:错误绑定参数1-可能不受支持的类型.上面的异常是以下异常的直接原因:追溯(最近一次通话):_bootstrap_inner中的文件"D:\ Everyday_Uses \ lib \ threading.py",第954行self.run()运行中的文件"D:\ Everyday_Uses \ lib \ threading.py",第892行self._target(* self._args,** self._kwargs)_handle_event_internal中的文件"D:\ Everyday_Uses \ lib \ site-packages \ socketio \ server.py",行680r = server._trigger_event(数据[0],名称空间,sid,*数据[1:])_trigger_event中的文件"D:\ Everyday_Uses \ lib \ site-packages \ socketio \ server.py",行704返回self.handlers [namespace] [event](* args)_handler中的文件"D:\ Everyday_Uses \ lib \ site-packages \ flask_socketio \ __ init__.py",第283行返回self._handle_event(处理程序,消息,名称空间,sid,_handle_event中的文件"D:\ Everyday_Uses \ lib \ site-packages \ flask_socketio \ __ init__.py",第751行ret =处理程序(* args)装饰后的视图中的文件"D:\ Everyday_Uses \ lib \ site-packages \ flask_login \ utils.py",第272行return func(* args,** kwargs)文字中的文件"d:\ Everyday_Uses \ Programming \ SparkWIT \ main.py",第200行db.session.commit()文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ scoping.py",第163行,在do返回getattr(self.registry(),name)(* args,** kwargs)提交中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ session.py",行1042self.transaction.commit()提交中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ session.py",第504行self._prepare_impl()_prepare_impl中的第483行"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ session.py"self.session.flush()文件" C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ session.py',第2536行self._flush(对象)_flush中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ session.py",行2678transaction.rollback(_capture_exception =真实)__exit__中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ util \ langhelpers.py",第68行compat.raise_(在第182行中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ util \ compat.py",第182行提出例外_flush中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ session.py",行2638flush_context.execute()执行中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ unitofwork.py",第422行rec.execute(个体)执行中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ unitofwork.py",行586persistence.save_obj(save_obj中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ persistence.py",第239行_emit_insert_statements(_emit_insert_statements中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ orm \ persistence.py",行1135结果= cached_connections [连接] .execute(执行中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ base.py",行1011返回meth(self,multiparams,params)_execute_on_connection中的文件``C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ sql \ elements.py''行298返回连接._execute_clauseelement(自己,多参数,参数)_execute_clauseelement中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ base.py",行1124ret = self._execute_context(_execute_context中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ base.py",行1316self._handle_dbapi_exception(_handle_dbapi_exception util.raise_中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ base.py",第1510行在第182行中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ util \ compat.py",第182行提出例外_execute_context中的文件"C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ base.py",行1276self.dialect.do_execute(do_execute中的文件``C:\ Users \ aarya \ AppData \ Roaming \ Python \ Python39 \ site-packages \ sqlalchemy \ engine \ default.py'',第593行cursor.execute(语句,参数)sqlalchemy.exc.InterfaceError:(sqlite3.InterfaceError)错误绑定参数1-可能是不受支持的类型.[SQL:将消息插入(room_id,内容)值(?,?)[参数:('test',{'msg':'gsefasd'})](有关此错误的背景,请访问:http://sqlalche.me/e/13/rvf5) 

解决方案

我没有正确阅读您的代码,但是读完您的问题后我想到的是.您可以为每个房间ID创建一个临时存储,并且每次有人创建新消息时,都会将该消息添加到与房间ID相对应的该临时存储中.现在,只要有人加入会议室,便会读取与该会议室ID相关联的所有消息,并将其传递给模板.对于一个简单的实现,它可以是一个字典,但是对于一个好的实现,您可能想要使用不基于SQL数据库的文档.如果您不想永久存储消息,则可以在所有人离开后删除与该会议室ID关联的文档.

存储结构:

  {Roomid:[{msgid:1,msg:'xyz',发件人姓名:'xyz'}]}} 

由于您已经在为用户使用数据库,因此也可以使用它.为消息创建类,例如:

  class消息(db.Model):id = db.Column(db.Integer,primary_key = True)room_id = db.Column(db.Integer,unique = True,nullable = False)#添加其他必填字段 

此后,我们需要修改发出新创建的消息的方法

  @ socketio.on('text',namespace ='/chat')@需要登录def文字(消息):房间= session.get('房间')msg =消息(roomid = romm,内容= message)db.session.add(msg)db.session.commit()发出('message',{'msg':session.get('username')+':'+ message ['msg']},room = room) 

现在我们创建一个api,它将向我们返回特定room_id的消息

  @ app.route('/get_messages/< room_id>')def message_handler(room_id):消息= Message.query.filter_by(room_id = room_id)#根据需要将它们放入适当的结构返回讯息 

最后,无论您将用户连接到套接字并使用JavaScript将用户连接到房间的任何位置,都使用room_id向此get_messages路由发出AJAX请求,并更新屏幕上返回的消息.

另外,如果还存储消息的时间并在返回前对它们进行排序,最好在message_handler函数中进行排序.

我已经检查了您的代码,发现了一些差异.

编辑2

首先,请正确命名变量,您已将传递给函数message的参数命名为新消息,并将新创建的对象命名为message,这样会产生问题.

现在出错的原因是,编写发射代码时,您正在传递message ['msg'],但是在创建对象时,您只是传递了content = message,这是错误的,因为message是一个字典,并且模型要求它传递是字符串.如果您在堆栈跟踪中查找到底出了什么问题,它将显示正在插入的值,并显示:

  [SQL:将INERT消息插入(room_id,内容)值(?,?)][参数:('test',{'msg':'gsefasd'})] 

这清楚地表明房间ID是字符串"test",但是提供的内容是字典.我要说的是,总是对发生的错误有个很好的了解,通常它们会提供很多帮助.

因此更改后的代码将是

  @ socketio.on('text',namespace ='/chat')@需要登录def文字(消息):房间= session.get('房间')new_message =消息(room_id = room,content = message ['msg'])db.session.add(new_message)db.session.commit()发出('message',{'msg':session.get('username')+':'+ message ['msg']},room = room) 

I am trying to implement a feature in my flask app where users can create or join a room and chat with each other. I have established the part where users can chat, create and join rooms, but I also want to add chat history depending on the room they are in so that when a new user joins or leaves and joins, they can see all the previous messages specific to the chat room they are in. I started with crating a class to store the messages. Then, I simply tried to save those messages everytime a new message was sent. For some reason, I keep getting an error. If someone could help me solve this issue and help me add the chat history, it would be greatly appreciated. The code and the error is down below.

main.py

    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 Messages(db.Model, UserMixin):
        id = db.Column(db.Integer, primary_key=True)
        room_id = db.Column(db.String(1200), unique=True, nullable=False)
        content = db.Column(db.String(10000))

    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()

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

    @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')

        message = Messages(room_id=room, content=message)
        db.session.add(message)
        db.session.commit()
        emit('message', {'msg': session.get('username') + ' : ' + message['msg']}, room=room)

    @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, debug=True)

chat.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 %}

chatselection.html

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

{% block content %}

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


{% endblock %}

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 + '/chat');
                    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://media.istockphoto.com/photos/abstract-glittering-dna-helix-with-depth-of-field-over-dark-space-picture-id1201193016?k=6&m=1201193016&s=612x612&w=0&h=_H80RaLa4OYIiT136j_cFgm-YRHAiV4wmaSkSKAMFbQ=)">
            <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>

This is the error I'm getting by the way.

    Exception in thread Thread-32:
    Traceback (most recent call last):
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\base.py", line 1276, in _execute_context       
        self.dialect.do_execute(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\default.py", line 593, in do_execute
        cursor.execute(statement, parameters)
    sqlite3.InterfaceError: Error binding parameter 1 - probably unsupported type.

    The above exception was the direct cause of the following exception:

    Traceback (most recent call last):
    File "D:\Everyday_Uses\lib\threading.py", line 954, in _bootstrap_inner
        self.run()
    File "D:\Everyday_Uses\lib\threading.py", line 892, in run
        self._target(*self._args, **self._kwargs)
    File "D:\Everyday_Uses\lib\site-packages\socketio\server.py", line 680, in _handle_event_internal
        r = server._trigger_event(data[0], namespace, sid, *data[1:])
    File "D:\Everyday_Uses\lib\site-packages\socketio\server.py", line 704, in _trigger_event
        return self.handlers[namespace][event](*args)
    File "D:\Everyday_Uses\lib\site-packages\flask_socketio\__init__.py", line 283, in _handler
        return self._handle_event(handler, message, namespace, sid,
    File "D:\Everyday_Uses\lib\site-packages\flask_socketio\__init__.py", line 751, in _handle_event
        ret = handler(*args)
    File "D:\Everyday_Uses\lib\site-packages\flask_login\utils.py", line 272, in decorated_view
        return func(*args, **kwargs)
    File "d:\Everyday_Uses\Programming\SparkWIT\main.py", line 200, in text
        db.session.commit()
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\scoping.py", line 163, in do
        return getattr(self.registry(), name)(*args, **kwargs)
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\session.py", line 1042, in commit
        self.transaction.commit()
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\session.py", line 504, in commit
        self._prepare_impl()
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\session.py", line 483, in _prepare_impl
        self.session.flush()
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\session.py", line 2536, in flush
        self._flush(objects)
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\session.py", line 2678, in _flush
        transaction.rollback(_capture_exception=True)
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\util\langhelpers.py", line 68, in __exit__
        compat.raise_(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\util\compat.py", line 182, in raise_
        raise exception
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\session.py", line 2638, in _flush
        flush_context.execute()
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\unitofwork.py", line 422, in execute
        rec.execute(self)
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\unitofwork.py", line 586, in execute
        persistence.save_obj(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\persistence.py", line 239, in save_obj
        _emit_insert_statements(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\orm\persistence.py", line 1135, in _emit_insert_statements
        result = cached_connections[connection].execute(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\base.py", line 1011, in execute
        return meth(self, multiparams, params)
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\sql\elements.py", line 298, in _execute_on_connection 
        return connection._execute_clauseelement(self, multiparams, params)
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\base.py", line 1124, in _execute_clauseelement 
        ret = self._execute_context(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\base.py", line 1316, in _execute_context       
        self._handle_dbapi_exception(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\base.py", line 1510, in _handle_dbapi_exception    util.raise_(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\util\compat.py", line 182, in raise_
        raise exception
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\base.py", line 1276, in _execute_context
        self.dialect.do_execute(
    File "C:\Users\aarya\AppData\Roaming\Python\Python39\site-packages\sqlalchemy\engine\default.py", line 593, in do_execute
        cursor.execute(statement, parameters)
    sqlalchemy.exc.InterfaceError: (sqlite3.InterfaceError) Error binding parameter 1 - probably unsupported type.
    [SQL: INSERT INTO messages (room_id, content) VALUES (?, ?)]
    [parameters: ('test', {'msg': 'gsefasd'})]
    (Background on this error at: http://sqlalche.me/e/13/rvf5)

解决方案

I haven't properly gone through your code but what comes to my mind after reading your question is. You can create a temporary storage for each room id and every time a new message is created by anyone add that message to that temporary storage corresponding to the room id. And now whenever someone joins the room read all messages associated with that room id and pass it to template. For a simple implementation it can be a dictionary but for a good implementation you might want to use a document based no SQL database. If you dont want to store the messages permanently you can delete the documents associated with that room id once everyone leaves.

Storage structure:

 { Roomid: [{ msgid: 1, msg : 'xyz', sendername: 'xyz'}]}

Edit:

Since you are already using a database for users you can use it as well. Create a class for messages like:

class Message(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    room_id = db.Column(db.Integer, unique=True, nullable=False)
    #add other required fields

After this we need to modify the method which emits the newly created message

@socketio.on('text', namespace='/chat')
@login_required
def text(message):
    room = session.get('room')
    msg = Message(roomid= romm, content=message)
    db.session.add(msg)
    db.session.commit()
    emit('message', {'msg': session.get('username') + ' : ' + message['msg']}, room=room)

Now we create an api which will return us messages of a specific room_id

@app.route('/get_messages/<room_id>')
def message_handler(room_id):
    messages = Message.query.filter_by(room_id = room_id)
    #Get them into proper structure as you want
    return messages

And finally wherever you are connecting the user to socket and joining the user to a room in JavaScript make an AJAX request to this get_messages route with the room_id and update the message returned on the screen.

Also it would be better if you also store the time of message and sort the messages in message_handler function before returning them.

I have gone through your code and i have found some discrepancies.

Edit 2

First of all please name variables properly you have named the parameter passed to function message as well as the newly created object as message so it will create problems.

Now the reason for error is that when writing the emit code you are passing message['msg'] but while creating the object you have simply passed content=message which is wrong because message is a dictionary and the model requires it to be string. If you go through the stack trace for what went wrong at the end it shows what values were being inserted and it shows:

[SQL: INSERT INTO messages (room_id, content) VALUES (?, ?)]
[parameters: ('test', {'msg': 'gsefasd'})]

This clearly shows that the room id is a string 'test', but the content provided is a dictionary. I will say always have a good look at whatever error occurs usually they have hints which help a lot.

So the code after making changes will be

@socketio.on('text', namespace='/chat')
@login_required
def text(message):
    room = session.get('room')

    new_message = Messages(room_id=room, content=message['msg'])
    db.session.add(new_message)
    db.session.commit()
    emit('message', {'msg': session.get('username') + ' : ' + message['msg']}, room=room)

这篇关于Flask:如何根据烧瓶中的聊天室添加聊天记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆