You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Python登录系统实现用户大厅/群组的创建、加入及专属功能调用?

实现带大厅/群组功能的Python登录系统扩展方案

基于你已有的用户登录系统,我们可以通过扩展数据库结构、实现核心群组功能、添加权限校验这三步来完成需求,以下是具体实现细节:

1. 数据库表结构扩展

你需要在现有用户表基础上新增三张表,用来存储大厅信息、用户与大厅的关联、以及邀请记录:

  • halls(大厅表):

    • id:主键,唯一标识大厅
    • name:大厅名称(必填)
    • owner_id:关联用户表的创建者ID(外键)
    • created_at:大厅创建时间(默认当前时间)
    • description:可选,大厅描述字段
  • user_hall_relations(用户-大厅关联表):

    • user_id:关联用户ID(外键,联合主键)
    • hall_id:关联大厅ID(外键,联合主键)
    • role:用户在大厅的角色(比如owner/admin/member,默认member)
    • joined_at:用户加入时间(默认当前时间)
  • hall_invites(邀请记录表):

    • id:主键
    • hall_id:关联大厅ID(外键)
    • inviter_id:邀请者ID(外键)
    • invitee_email:被邀请者邮箱(匹配用户表的邮箱字段)
    • code:唯一邀请码(用于验证)
    • status:邀请状态(pending/accepted/rejected,默认pending)
    • expired_at:邀请过期时间(默认7天后)

2. 核心功能代码实现

下面用SQLAlchemy ORM示例(如果你用原生SQL,逻辑完全一致,只是语法不同):

2.1 创建大厅

登录用户创建大厅后,自动成为大厅所有者并加入:

import datetime
import uuid
from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

Base = declarative_base()

# 假设你已有的User模型
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String(50), unique=True)
    email = Column(String(100), unique=True)

class Hall(Base):
    __tablename__ = 'halls'
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)
    owner_id = Column(Integer, ForeignKey('users.id'))
    created_at = Column(DateTime, default=datetime.datetime.utcnow)
    owner = relationship('User')

class UserHallRelation(Base):
    __tablename__ = 'user_hall_relations'
    user_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
    hall_id = Column(Integer, ForeignKey('halls.id'), primary_key=True)
    role = Column(String(20), default='member')
    joined_at = Column(DateTime, default=datetime.datetime.utcnow)

# 初始化数据库会话
engine = create_engine('sqlite:///your_database.db')
Session = sessionmaker(bind=engine)
db_session = Session()

def create_hall(user_id, hall_name, description=None):
    # 校验用户存在
    user = db_session.query(User).filter_by(id=user_id).first()
    if not user:
        raise ValueError("用户不存在")
    # 创建大厅
    new_hall = Hall(name=hall_name, owner_id=user_id)
    db_session.add(new_hall)
    db_session.commit()
    # 绑定创建者到大厅
    owner_relation = UserHallRelation(user_id=user_id, hall_id=new_hall.id, role='owner')
    db_session.add(owner_relation)
    db_session.commit()
    return new_hall.id

2.2 邀请与接受邀请

邀请者必须是大厅成员,被邀请者通过邮箱匹配验证:

class HallInvite(Base):
    __tablename__ = 'hall_invites'
    id = Column(Integer, primary_key=True)
    hall_id = Column(Integer, ForeignKey('halls.id'))
    inviter_id = Column(Integer, ForeignKey('users.id'))
    invitee_email = Column(String(100))
    code = Column(String(64), unique=True)
    status = Column(String(20), default='pending')
    expired_at = Column(DateTime, default=lambda: datetime.datetime.utcnow() + datetime.timedelta(days=7))

def send_hall_invite(inviter_id, hall_id, invitee_email):
    # 校验邀请者是否在大厅内
    inviter_in_hall = db_session.query(UserHallRelation).filter_by(user_id=inviter_id, hall_id=hall_id).first()
    if not inviter_in_hall:
        raise ValueError("你不是该大厅成员,无法发送邀请")
    # 生成唯一邀请码
    invite_code = str(uuid.uuid4())
    new_invite = HallInvite(
        hall_id=hall_id,
        inviter_id=inviter_id,
        invitee_email=invitee_email,
        code=invite_code
    )
    db_session.add(new_invite)
    db_session.commit()
    # 这里可以加发送邮件的逻辑,把invite_code发给被邀请者邮箱
    return invite_code

def accept_hall_invite(user_id, invite_code):
    # 校验邀请有效性
    invite = db_session.query(HallInvite).filter_by(code=invite_code, status='pending').first()
    if not invite or datetime.datetime.utcnow() > invite.expired_at:
        raise ValueError("邀请无效或已过期")
    # 校验被邀请者是当前用户
    user = db_session.query(User).filter_by(id=user_id, email=invite.invitee_email).first()
    if not user:
        raise ValueError("该邀请不属于你")
    # 校验用户未加入该大厅
    already_joined = db_session.query(UserHallRelation).filter_by(user_id=user_id, hall_id=invite.hall_id).first()
    if already_joined:
        raise ValueError("你已加入该大厅")
    # 添加用户到大厅
    new_relation = UserHallRelation(user_id=user_id, hall_id=invite.hall_id)
    db_session.add(new_relation)
    # 更新邀请状态
    invite.status = 'accepted'
    db_session.commit()

2.3 直接加入大厅(公开场景)

如果是公开大厅,允许用户直接申请加入:

def join_hall_directly(user_id, hall_id):
    # 校验大厅存在
    hall = db_session.query(Hall).filter_by(id=hall_id).first()
    if not hall:
        raise ValueError("大厅不存在")
    # 校验用户未加入
    already_joined = db_session.query(UserHallRelation).filter_by(user_id=user_id, hall_id=hall_id).first()
    if already_joined:
        raise ValueError("你已加入该大厅")
    # 添加关联
    new_relation = UserHallRelation(user_id=user_id, hall_id=hall_id)
    db_session.add(new_relation)
    db_session.commit()

3. 权限控制与大厅专属函数

要确保只有大厅内用户能调用专属函数,并且函数仅影响大厅成员:

3.1 权限校验工具

写一个通用的校验函数,或者用装饰器简化重复逻辑:

def is_user_in_hall(user_id, hall_id):
    return bool(db_session.query(UserHallRelation).filter_by(user_id=user_id, hall_id=hall_id).first())

# 装饰器:要求用户必须是大厅成员
def require_hall_member(func):
    def wrapper(user_id, hall_id, *args, **kwargs):
        if not is_user_in_hall(user_id, hall_id):
            raise PermissionError("你不属于该大厅,无法执行此操作")
        return func(user_id, hall_id, *args, **kwargs)
    return wrapper

# 装饰器:要求用户是大厅所有者
def require_hall_owner(func):
    def wrapper(user_id, hall_id, *args, **kwargs):
        relation = db_session.query(UserHallRelation).filter_by(user_id=user_id, hall_id=hall_id, role='owner').first()
        if not relation:
            raise PermissionError("仅大厅所有者可执行此操作")
        return func(user_id, hall_id, *args, **kwargs)
    return wrapper

3.2 实现大厅专属函数

比如发送大厅通知、统计成员、修改大厅名称等:

@require_hall_member
def send_hall_announcement(user_id, hall_id, content):
    # 获取所有大厅成员ID
    member_ids = [rel.user_id for rel in db_session.query(UserHallRelation).filter_by(hall_id=hall_id).all()]
    # 这里实现通知逻辑,比如插入通知表、推送消息等,仅针对这些member_ids
    print(f"向大厅{hall_id}的成员{member_ids}发送公告:{content}")

@require_hall_member
def get_hall_member_list(user_id, hall_id):
    members = db_session.query(User).join(UserHallRelation).filter(UserHallRelation.hall_id == hall_id).all()
    return [{"id": u.id, "username": u.username} for u in members]

@require_hall_owner
def rename_hall(user_id, hall_id, new_name):
    hall = db_session.query(Hall).filter_by(id=hall_id).first()
    hall.name = new_name
    db_session.commit()

4. Web场景下的会话处理(可选)

如果是Web应用(比如Flask/Django),需要从请求会话中获取当前登录用户ID,示例用Flask:

from flask import Flask, session, request, jsonify

app = Flask(__name__)
app.secret_key = 'your_secret_key_here'

# 创建大厅接口
@app.route('/api/halls', methods=['POST'])
def api_create_hall():
    if 'user_id' not in session:
        return jsonify({"error": "请先登录"}), 401
    data = request.get_json()
    hall_name = data.get('name')
    try:
        hall_id = create_hall(session['user_id'], hall_name)
        return jsonify({"hall_id": hall_id, "message": "大厅创建成功"}), 200
    except ValueError as e:
        return jsonify({"error": str(e)}), 400

# 接受邀请接口
@app.route('/api/halls/invite/<invite_code>', methods=['POST'])
def api_accept_invite(invite_code):
    if 'user_id' not in session:
        return jsonify({"error": "请先登录"}), 401
    try:
        accept_hall_invite(session['user_id'], invite_code)
        return jsonify({"message": "成功加入大厅"}), 200
    except ValueError as e:
        return jsonify({"error": str(e)}), 400

内容的提问来源于stack exchange,提问作者jeff425

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:15:41