用python写了个单文件版的家族族谱管理系统,有喜欢的吗?资源已上传

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

过年那会儿,看着家族的子孙辈的孩子们一大群来拜年,竟然还有好多叫不上名字,再看看垂垂老矣的父母,想着很多年前做了一个家族的通讯录,何不做一个家族的管理系统来,本身也算是一种传承吧,当然了,真正的家谱那是有严格的规格和规则限制的,我这个纯属于只为了记录的一种的家谱形式而已。

家族族谱管理系统是一款专为个人和家族设计的本地单机应用,用于记录和管理家族成员信息、血缘关系、家族历史等数据。

主要功能
  • 家族成员信息管理(添加、编辑、删除)
  • 血缘关系可视化展示(家族树)
  • 家族历史事件记录
  • 家族成员照片管理
开发目的

本系统的开发旨在:

  • 帮助家族记录和传承家族文化
  • 提供直观、易用的家族树可视化工具
  • 确保家族数据的安全存储和管理
  • 促进家族成员之间的联系和了解
技术栈

本系统基于以下技术开发:

  • 前端:HTML5, CSS3, JavaScript, Bootstrap 5
  • 后端:Python, Flask, SQLAlchemy
  • 数据库:SQLite
  • 打包工具:PyInstaller

界面如图:

单文件可以单机使用,为了您的意思安全,建议单机使用,随用隋开,不用关上就好了。当然了,也支持多用户。数据库自己保存好就行。

为了测试数据,我就拿了朱元璋的临时举个例子。

家族成员列表页面

按辈分显示的家族列表页面

家族树

感觉以上这样可还行?

3. 项目结构

Family/

├── app.py              # 主应用文件

├── family_tree.spec    # PyInstaller 打包配置

├── pdf_generator.py    # PDF 生成模块

├── templates/          # 模板文件

│   ├── base.html       # 基础模板

│   ├── index.html      # 首页

│   ├── dashboard.html  # 仪表盘

│   ├── family_tree.html # 家族树页面

│   ├── profile.html    # 个人信息页面

│   ├── disclaimer.html # 免责声明页面

│   └── about.html      # 关于本系统页面

├── static/             # 静态文件

│   ├── css/            # CSS 文件

│   ├── js/             # JavaScript 文件

│   ├── webfonts/       # 字体文件

│   ├── uploads/        # 上传文件

│   └── icon files      # 图标文件

└── instance/           # 数据库文件

    └── family_tree.db  # SQLite 数据库

代码部分

class Family(db.Model):
    """家族模型"""
    __tablename__ = 'families'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # 删除状态
    is_deleted = db.Column(db.Boolean, default=False)
    deleted_at = db.Column(db.DateTime)
    deleted_by = db.Column(db.Integer, db.ForeignKey('users.id'))
    is_permanently_deleted = db.Column(db.Boolean, default=False)  # 是否彻底删除
    
    # 关联
    members = db.relationship('FamilyMember', backref='family', lazy=True, cascade='all, delete-orphan')

class FamilyMember(db.Model):
    """家族成员模型"""
    __tablename__ = 'family_members'
    id = db.Column(db.Integer, primary_key=True)
    family_id = db.Column(db.Integer, db.ForeignKey('families.id'), nullable=False)
    created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    
    # 基本信息
    name = db.Column(db.String(100), nullable=False)
    gender = db.Column(db.String(10), nullable=False)  # 'male', 'female'
    birth_date = db.Column(db.Date)
    death_date = db.Column(db.Date)
    is_alive = db.Column(db.Boolean, default=True)
    
    # 联系方式
    phone = db.Column(db.String(20))
    email = db.Column(db.String(120))
    address = db.Column(db.Text)
    wechat = db.Column(db.String(50))
    wechat_qr = db.Column(db.String(255))
    
    # 职业信息
    occupation = db.Column(db.String(100))
    company = db.Column(db.String(100))
    title = db.Column(db.String(50))
    
    # 个人信息
    biography = db.Column(db.Text)
    personality = db.Column(db.Text)
    achievements = db.Column(db.Text)
    
    # 墓地信息(非健在人员)
    cemetery_location = db.Column(db.Text)
    
    # 照片
    photo = db.Column(db.String(255))
    
    # 树形结构 - 邻接表模式
    parent_id = db.Column(db.Integer, db.ForeignKey('family_members.id'), nullable=True)
    generation = db.Column(db.Integer, default=0)  # 辈分代数
    order_in_siblings = db.Column(db.Integer, default=0)  # 在同辈中的排序
    
    # 关系类型 - 用于标识非血亲关系
    relation_type = db.Column(db.String(50), default='blood')  # blood:血亲, adopted:收养, step:继亲, god:义亲, clan:宗族, master:师徒, sworn:结拜, friend:世交
    
    # 元数据
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # 关联
    children = db.relationship('FamilyMember', backref=db.backref('parent', remote_side=[id]), lazy=True)
    spouse_relationships = db.relationship('SpouseRelationship', foreign_keys='SpouseRelationship.member1_id', backref='member1', lazy=True)
    
    def to_dict(self, include_relations=False):
        """转换为字典"""
        # 检查是否有用户关联,如果有则使用用户的照片
        photo = self.photo
        if not photo:
            # 查找与该成员关联的用户
            user_relation = UserFamilyRelation.query.filter_by(member_id=self.id).first()
            if user_relation and user_relation.user.photo:
                photo = user_relation.user.photo
        
        data = {
            'id': self.id,
            'family_id': self.family_id,
            'name': self.name,
            'gender': self.gender,
            'birth_date': self.birth_date.strftime('%Y-%m-%d') if self.birth_date else None,
            'death_date': self.death_date.strftime('%Y-%m-%d') if self.death_date else None,
            'is_alive': self.is_alive,
            'phone': self.phone,
            'email': self.email,
            'address': self.address,
            'wechat': self.wechat,
            'wechat_qr': self.wechat_qr,
            'occupation': self.occupation,
            'company': self.company,
            'title': self.title,
            'biography': self.biography,
            'personality': self.personality,
            'achievements': self.achievements,
            'cemetery_location': self.cemetery_location,
            'photo': photo,
            'parent_id': self.parent_id,
            'generation': self.generation,
            'order_in_siblings': self.order_in_siblings,
            'relation_type': self.relation_type,
            'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
        }
        
        if include_relations:
            # 获取配偶(双向查询)
            spouses = []
            # 查询作为member1的关系
            for rel in self.spouse_relationships:
                spouse = db.session.get(FamilyMember, rel.member2_id)
                if spouse:
                    # 检查配偶是否有照片,如果没有则查找关联用户的照片
                    spouse_photo = spouse.photo
                    if not spouse_photo:
                        user_relation = UserFamilyRelation.query.filter_by(member_id=spouse.id).first()
                        if user_relation and user_relation.user.photo:
                            spouse_photo = user_relation.user.photo
                    
                    spouses.append({
                        'id': spouse.id,
                        'name': spouse.name,
                        'birth_date': spouse.birth_date.strftime('%Y-%m-%d') if spouse.birth_date else None,
                        'death_date': spouse.death_date.strftime('%Y-%m-%d') if spouse.death_date else None,
                        'gender': spouse.gender,
                        'is_alive': spouse.is_alive,
                        'address': spouse.address,
                        'cemetery_location': spouse.cemetery_location,
                        'occupation': spouse.occupation,
                        'phone': spouse.phone,
                        'email': spouse.email,
                        'wechat': spouse.wechat,
                        'photo': spouse_photo,
                        'relationship_type': rel.relationship_type,
                        'generation': spouse.generation
                    })
            # 查询作为member2的关系
            for rel in SpouseRelationship.query.filter_by(member2_id=self.id).all():
                spouse = db.session.get(FamilyMember, rel.member1_id)
                if spouse:
                    # 检查配偶是否有照片,如果没有则查找关联用户的照片
                    spouse_photo = spouse.photo
                    if not spouse_photo:
                        user_relation = UserFamilyRelation.query.filter_by(member_id=spouse.id).first()
                        if user_relation and user_relation.user.photo:
                            spouse_photo = user_relation.user.photo
                    
                    spouses.append({
                        'id': spouse.id,
                        'name': spouse.name,
                        'birth_date': spouse.birth_date.strftime('%Y-%m-%d') if spouse.birth_date else None,
                        'death_date': spouse.death_date.strftime('%Y-%m-%d') if spouse.death_date else None,
                        'gender': spouse.gender,
                        'is_alive': spouse.is_alive,
                        'address': spouse.address,
                        'cemetery_location': spouse.cemetery_location,
                        'occupation': spouse.occupation,
                        'phone': spouse.phone,
                        'email': spouse.email,
                        'wechat': spouse.wechat,
                        'photo': spouse_photo,
                        'relationship_type': rel.relationship_type,
                        'generation': spouse.generation
                    })
            data['spouses'] = spouses
            
            # 获取子女
            children = []
            for child in self.children:
                children.append({
                    'id': child.id,
                    'name': child.name,
                    'gender': child.gender
                })
            data['children'] = children
            
        return data

class SpouseRelationship(db.Model):
    """配偶关系模型"""
    __tablename__ = 'spouse_relationships'
    id = db.Column(db.Integer, primary_key=True)
    member1_id = db.Column(db.Integer, db.ForeignKey('family_members.id'), nullable=False)
    member2_id = db.Column(db.Integer, db.ForeignKey('family_members.id'), nullable=False)
    relationship_type = db.Column(db.String(20), default='spouse')  # 'husband', 'wife', 'spouse'
    marriage_date = db.Column(db.Date)
    is_current = db.Column(db.Boolean, default=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

class MemberRelation(db.Model):
    """成员关系闭包表 - 用于快速查询亲属关系"""
    __tablename__ = 'member_relations'
    id = db.Column(db.Integer, primary_key=True)
    ancestor_id = db.Column(db.Integer, db.ForeignKey('family_members.id'), nullable=False)
    descendant_id = db.Column(db.Integer, db.ForeignKey('family_members.id'), nullable=False)
    distance = db.Column(db.Integer, default=0)  # 距离(辈分差)
    relation_type = db.Column(db.String(50))  # 关系类型
    
    __table_args__ = (db.UniqueConstraint('ancestor_id', 'descendant_id', name='unique_relation'),)
def calculate_generation(member_id):
    """计算成员的辈分"""
    member = db.session.get(FamilyMember, member_id)
    if not member:
        return 0
    
    if not member.parent_id:
        return 0
    
    generation = 0
    current = member
    while current.parent_id:
        generation += 1
        current = db.session.get(FamilyMember, current.parent_id)
    
    return generation

def get_ancestors(member_id, max_depth=10):
    """获取所有祖先"""
    ancestors = []
    current_id = member_id
    depth = 0
    
    while current_id and depth < max_depth:
        member = db.session.get(FamilyMember, current_id)
        if not member or not member.parent_id:
            break
        parent = db.session.get(FamilyMember, member.parent_id)
        if parent:
            ancestors.append(parent)
            current_id = parent.id
        else:
            break
        depth += 1
    
    return ancestors

def get_descendants(member_id, max_depth=10):
    """获取所有后代"""
    descendants = []
    queue = [(member_id, 0)]
    
    while queue:
        current_id, depth = queue.pop(0)
        if depth >= max_depth:
            continue
        
        children = FamilyMember.query.filter_by(parent_id=current_id).all()
        for child in children:
            descendants.append((child, depth + 1))
            queue.append((child.id, depth + 1))
    
    return descendants

def find_common_ancestor(member1_id, member2_id):
    """查找两个成员的共同祖先"""
    ancestors1 = {member1_id: 0}
    current_id = member1_id
    depth = 0
    
    # 获取member1的所有祖先
    while True:
        member = db.session.get(FamilyMember, current_id)
        if not member or not member.parent_id:
            break
        depth += 1
        ancestors1[member.parent_id] = depth
        current_id = member.parent_id
    
    # 检查member2及其祖先
    if member2_id in ancestors1:
        return member2_id, ancestors1[member2_id], 0
    
    current_id = member2_id
    depth2 = 0
    while True:
        member = db.session.get(FamilyMember, current_id)
        if not member or not member.parent_id:
            break
        depth2 += 1
        if member.parent_id in ancestors1:
            return member.parent_id, ancestors1[member.parent_id], depth2
        current_id = member.parent_id
    
    return None, 0, 0
def build_family_tree(family_id, root_id=None, max_depth=10):
    """构建家族树结构"""
    if root_id:
        root = db.session.get(FamilyMember, root_id)
    else:
        # 找到根节点(没有parent的节点中最早创建的)
        root = FamilyMember.query.filter_by(family_id=family_id, parent_id=None).order_by(FamilyMember.created_at).first()
    
    if not root:
        return None
    
    def build_node(member, depth=0):
        if depth >= max_depth:
            return None
        
        node = member.to_dict(include_relations=True)
        node['depth'] = depth
        
        # 获取配偶信息(双向查询)
        spouses = []
        # 查询 member1_id 是当前成员的情况
        for rel in SpouseRelationship.query.filter_by(member1_id=member.id).all():
            spouse = db.session.get(FamilyMember, rel.member2_id)
            if spouse:
                spouses.append({
                    'id': spouse.id,
                    'name': spouse.name,
                    'gender': spouse.gender,
                    'photo': spouse.photo,
                    'birth_date': spouse.birth_date.strftime('%Y-%m-%d') if spouse.birth_date else None,
                    'death_date': spouse.death_date.strftime('%Y-%m-%d') if spouse.death_date else None,
                    'is_alive': spouse.is_alive,
                    'occupation': spouse.occupation,
                    'generation': spouse.generation,
                    'relationship_type': rel.relationship_type
                })
        # 查询 member2_id 是当前成员的情况
        for rel in SpouseRelationship.query.filter_by(member2_id=member.id).all():
            spouse = db.session.get(FamilyMember, rel.member1_id)
            if spouse:
                spouses.append({
                    'id': spouse.id,
                    'name': spouse.name,
                    'gender': spouse.gender,
                    'photo': spouse.photo,
                    'birth_date': spouse.birth_date.strftime('%Y-%m-%d') if spouse.birth_date else None,
                    'death_date': spouse.death_date.strftime('%Y-%m-%d') if spouse.death_date else None,
                    'is_alive': spouse.is_alive,
                    'occupation': spouse.occupation,
                    'generation': spouse.generation,
                    'relationship_type': rel.relationship_type
                })
        node['spouses'] = spouses
        
        # 递归获取子女
        children = []
        for child in FamilyMember.query.filter_by(parent_id=member.id).order_by(FamilyMember.order_in_siblings, FamilyMember.birth_date).all():
            child_node = build_node(child, depth + 1)
            if child_node:
                children.append(child_node)
        node['children'] = children
        
        return node
    
    return build_node(root)

这个其实很简单,就不多说了。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半熟的皮皮虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值