Python+PyQt5實現(xiàn)簡歷自動生成工具
一、概述:為什么需要自動化簡歷工具
在當今競爭激烈的求職市場中,一份專業(yè)、規(guī)范的簡歷是獲得面試機會的關(guān)鍵。然而,手動編寫和排版簡歷往往耗時費力,特別是當我們需要針對不同職位定制多份簡歷時。本文介紹的基于PyQt5的自動化簡歷生成工具,將徹底改變這一現(xiàn)狀。
該工具具有以下核心優(yōu)勢:
- 一站式管理:整合個人信息、教育背景、工作經(jīng)歷等所有模塊
- 可視化編輯:直觀的GUI界面,告別代碼和命令行
- 多格式輸出:支持PDF導出,確保跨平臺兼容性
- 數(shù)據(jù)持久化:JSON格式保存/加載,簡歷數(shù)據(jù)永不丟失
- 模板化設(shè)計:多種風格模板滿足不同行業(yè)需求
二、功能全景圖
2.1 核心功能模塊
模塊名稱 | 功能描述 | 技術(shù)實現(xiàn) |
---|---|---|
個人信息 | 收集基礎(chǔ)聯(lián)系方式和社交資料 | QLineEdit + QFormLayout |
教育經(jīng)歷 | 管理學歷、專業(yè)、GPA等信息 | QListWidget + 動態(tài)表單 |
工作經(jīng)歷 | 記錄職位、公司、工作描述 | 日期控件 + 富文本編輯 |
技能專長 | 分類展示技術(shù)棧和熟練度 | QComboBox + 層級列表 |
項目作品 | 展示項目成果和貢獻 | 超鏈接支持 + 多行文本 |
證書資質(zhì) | 管理專業(yè)認證信息 | 時間選擇器 + URL字段 |
語言能力 | 多語言水平標注 | 等級選擇器 |
2.2 特色功能
- 實時預(yù)覽:所見即所得的簡歷預(yù)覽功能
- 智能日期:"至今"選項自動處理日期顯示
- 響應(yīng)式布局:自適應(yīng)不同屏幕尺寸
- 主題配色:多套可視化主題隨時切換
- 數(shù)據(jù)校驗:關(guān)鍵字段自動驗證提醒
三、效果展示
UI界面概覽
左側(cè)為標簽式編輯面板,右側(cè)為實時預(yù)覽區(qū),符合專業(yè)軟件設(shè)計范式。
四、開發(fā)步驟詳解
4.1 環(huán)境配置
pip install PyQt5 fpdf
4.2 核心類設(shè)計
class ResumeGenerator(QMainWindow): def __init__(self): super().__init__() # 初始化UI和數(shù)據(jù) self.init_ui() self.init_resume_data() def init_ui(self): # 創(chuàng)建主窗口布局 self.setup_main_window() self.add_personal_info_tab() self.add_education_tab() # ...其他標簽頁 self.setup_preview_panel()
4.3 數(shù)據(jù)管理機制
采用三層架構(gòu)設(shè)計:
- 表示層:PyQt5界面組件
- 邏輯層:簡歷數(shù)據(jù)處理方法
- 持久層:JSON序列化存儲
五、關(guān)鍵代碼解析
5.1 動態(tài)表單管理
教育/工作經(jīng)歷采用列表+詳情表單的交互模式:
def add_education(self): edu = { "school": self.edu_school_edit.text(), "degree": self.edu_degree_edit.text(), # 其他字段... } self.resume_data["education"].append(edu) self.update_education_list()
5.2 PDF生成引擎
基于FPDF庫的定制化輸出:
def export_to_pdf(self): pdf = FPDF() pdf.add_page() # 設(shè)置中文字體支持 pdf.add_font('SimSun', '', 'simsun.ttc', uni=True) # 添加內(nèi)容區(qū)塊 self.add_personal_section(pdf) self.add_education_section(pdf) # ...其他部分 pdf.output("resume.pdf")
5.3 樣式管理系統(tǒng)
使用Qt樣式表實現(xiàn)現(xiàn)代化UI:
self.setStyleSheet(""" QMainWindow { background-color: #f0f2f5; } QTabBar::tab { padding: 10px; border-radius: 5px; } QPushButton { background-color: #4CAF50; color: white; } """)
六、完整源碼下載
import sys import json import os from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTextEdit, QPushButton, QComboBox, QListWidget, QListWidgetItem, QTabWidget, QFileDialog, QMessageBox, QFormLayout, QSpinBox, QDateEdit, QCheckBox, QGroupBox, QFrame) from PyQt5.QtCore import Qt, QDate from PyQt5.QtGui import QFont, QIcon, QColor, QPalette from fpdf import FPDF from datetime import datetime class ResumeGenerator(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("自動化簡歷生成工具") self.setGeometry(100, 100, 1000, 750) # 嘗試加載圖標,如果失敗則忽略 try: self.setWindowIcon(QIcon("resume_icon.png")) except: pass # 初始化UI self.init_ui() # 加載模板 self.load_templates() # 初始化簡歷數(shù)據(jù)結(jié)構(gòu) self.init_resume_data() # 當前編輯的項目索引 self.current_edu_index = -1 self.current_exp_index = -1 self.current_proj_index = -1 self.current_cert_index = -1 def init_ui(self): # 設(shè)置主窗口背景和全局樣式 self.setStyleSheet(""" QMainWindow { background-color: #f0f2f5; } QTabBar::tab { padding: 10px; border-top-left-radius: 5px; border-top-right-radius: 5px; margin-right: 2px; } QTabBar::tab:selected { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #ffffff, stop:1 #e0e0e0); border-bottom: 2px solid #4CAF50; } QTabBar::tab:!selected { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #e0e0e0, stop:1 #d0d0d0); } QLineEdit, QTextEdit, QComboBox, QSpinBox, QDateEdit { padding: 8px; border: 1px solid #ddd; border-radius: 4px; background: white; } QTextEdit { min-height: 100px; } QListWidget { border: 1px solid #ddd; background: white; border-radius: 4px; } QPushButton { padding: 8px 12px; border-radius: 4px; font-weight: bold; min-width: 80px; } QGroupBox { border: 1px solid #ddd; border-radius: 5px; margin-top: 10px; padding-top: 15px; background: white; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px; } """) # 主窗口布局 main_widget = QWidget() self.setCentralWidget(main_widget) main_layout = QHBoxLayout() main_widget.setLayout(main_layout) main_layout.setContentsMargins(10, 10, 10, 10) main_layout.setSpacing(15) # 左側(cè)面板 - 簡歷內(nèi)容編輯 (70%寬度) self.left_panel = QTabWidget() self.left_panel.setTabPosition(QTabWidget.North) self.left_panel.setDocumentMode(True) main_layout.addWidget(self.left_panel, 7) # 右側(cè)面板 - 預(yù)覽和操作 (30%寬度) right_panel = QWidget() right_panel.setMaximumWidth(350) right_layout = QVBoxLayout() right_layout.setContentsMargins(5, 5, 5, 5) right_panel.setLayout(right_layout) main_layout.addWidget(right_panel, 3) # 添加標簽頁 self.add_personal_info_tab() self.add_summary_tab() self.add_education_tab() self.add_experience_tab() self.add_skills_tab() self.add_projects_tab() self.add_certifications_tab() self.add_languages_tab() # 右側(cè)面板內(nèi)容 # 模板選擇組 template_group = QGroupBox("簡歷模板") template_layout = QVBoxLayout() template_group.setLayout(template_layout) self.template_combo = QComboBox() self.template_combo.setStyleSheet(""" QComboBox { padding: 8px; border: 1px solid #4CAF50; border-radius: 4px; background: white; } QComboBox::drop-down { border: none; } """) template_layout.addWidget(self.template_combo) # 操作按鈕組 button_group = QGroupBox("操作") button_layout = QVBoxLayout() button_group.setLayout(button_layout) # 預(yù)覽按鈕 self.preview_btn = QPushButton("?? 預(yù)覽簡歷") self.preview_btn.setStyleSheet(""" QPushButton { background-color: #4CAF50; color: white; } QPushButton:hover { background-color: #45a049; } """) self.preview_btn.clicked.connect(self.preview_resume) button_layout.addWidget(self.preview_btn) # 導出按鈕 self.export_btn = QPushButton("?? 導出PDF") self.export_btn.setStyleSheet(""" QPushButton { background-color: #2196F3; color: white; } QPushButton:hover { background-color: #0b7dda; } """) self.export_btn.clicked.connect(self.export_to_pdf) button_layout.addWidget(self.export_btn) # 分隔線 line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) button_layout.addWidget(line) # 保存按鈕 self.save_btn = QPushButton("?? 保存數(shù)據(jù)") self.save_btn.setStyleSheet(""" QPushButton { background-color: #FF9800; color: white; } QPushButton:hover { background-color: #e68a00; } """) self.save_btn.clicked.connect(self.save_resume_data) button_layout.addWidget(self.save_btn) # 加載按鈕 self.load_btn = QPushButton("?? 加載數(shù)據(jù)") self.load_btn.setStyleSheet(""" QPushButton { background-color: #9C27B0; color: white; } QPushButton:hover { background-color: #7b1fa2; } """) self.load_btn.clicked.connect(self.load_resume_data) button_layout.addWidget(self.load_btn) # 預(yù)覽區(qū)域組 preview_group = QGroupBox("簡歷預(yù)覽") preview_layout = QVBoxLayout() preview_group.setLayout(preview_layout) self.preview_text = QTextEdit() self.preview_text.setReadOnly(True) self.preview_text.setStyleSheet(""" QTextEdit { background-color: #f9f9f9; border: 1px solid #ddd; border-radius: 4px; } """) preview_layout.addWidget(self.preview_text) # 添加到右側(cè)面板 right_layout.addWidget(template_group) right_layout.addWidget(button_group) right_layout.addWidget(preview_group) # 設(shè)置標簽頁顏色 self.set_tab_colors() def set_tab_colors(self): #為每個標簽頁設(shè)置不同的顏色 tab_colors = [ ("#FF5252", "#FFFFFF"), # 紅色 ("#FF9800", "#FFFFFF"), # 橙色 ("#FFEB3B", "#000000"), # 黃色 ("#4CAF50", "#FFFFFF"), # 綠色 ("#2196F3", "#FFFFFF"), # 藍色 ("#673AB7", "#FFFFFF"), # 深紫色 ("#E91E63", "#FFFFFF"), # 粉色 ("#607D8B", "#FFFFFF") # 藍灰色 ] # 方法1:統(tǒng)一設(shè)置QTabBar樣式(推薦) tab_bar = self.left_panel.tabBar() tab_bar.setStyleSheet(""" QTabBar::tab { padding: 10px; border-top-left-radius: 5px; border-top-right-radius: 5px; margin-right: 2px; } QTabBar::tab:selected { background: white; border-bottom: 2px solid #4CAF50; } QTabBar::tab:!selected { background: #e0e0e0; } """) def init_resume_data(self): """初始化簡歷數(shù)據(jù)結(jié)構(gòu)""" self.resume_data = { "personal_info": { "name": "", "email": "", "phone": "", "address": "", "linkedin": "", "github": "", "website": "" }, "summary": "", "education": [], "experience": [], "skills": [], "projects": [], "certifications": [], "languages": [] } def add_personal_info_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) # 使用GroupBox組織內(nèi)容 group = QGroupBox("個人信息") form_layout = QFormLayout() group.setLayout(form_layout) # 創(chuàng)建帶圖標的輸入字段 self.name_edit = self.create_line_edit("??", "姓名") self.email_edit = self.create_line_edit("??", "郵箱") self.phone_edit = self.create_line_edit("??", "電話") self.address_edit = self.create_line_edit("??", "地址") self.linkedin_edit = self.create_line_edit("??", "LinkedIn") self.github_edit = self.create_line_edit("??", "GitHub") self.website_edit = self.create_line_edit("??", "個人網(wǎng)站") # 添加到表單 form_layout.addRow("姓名:", self.name_edit) form_layout.addRow("郵箱:", self.email_edit) form_layout.addRow("電話:", self.phone_edit) form_layout.addRow("地址:", self.address_edit) form_layout.addRow("LinkedIn:", self.linkedin_edit) form_layout.addRow("GitHub:", self.github_edit) form_layout.addRow("個人網(wǎng)站:", self.website_edit) layout.addWidget(group) layout.addStretch() self.left_panel.addTab(tab, "個人信息") def create_line_edit(self, icon, placeholder): """創(chuàng)建帶樣式的QLineEdit""" line_edit = QLineEdit() line_edit.setPlaceholderText(f"{icon} {placeholder}") line_edit.setStyleSheet(""" QLineEdit { padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; } QLineEdit:focus { border: 1px solid #4CAF50; } """) return line_edit def add_summary_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) group = QGroupBox("職業(yè)概述") group_layout = QVBoxLayout() group.setLayout(group_layout) self.summary_edit = QTextEdit() self.summary_edit.setPlaceholderText("在這里輸入你的職業(yè)概述...") self.summary_edit.setStyleSheet(""" QTextEdit { padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; } QTextEdit:focus { border: 1px solid #2196F3; } """) group_layout.addWidget(self.summary_edit) layout.addWidget(group) layout.addStretch() self.left_panel.addTab(tab, "職業(yè)概述") def add_education_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) # 教育經(jīng)歷表單組 form_group = QGroupBox("添加/編輯教育經(jīng)歷") form_layout = QFormLayout() form_group.setLayout(form_layout) # 創(chuàng)建輸入字段 self.edu_school_edit = self.create_line_edit("??", "學校名稱") self.edu_degree_edit = self.create_line_edit("??", "學位") self.edu_field_edit = self.create_line_edit("??", "專業(yè)") self.edu_start_date = QDateEdit() self.edu_end_date = QDateEdit() self.edu_current = QCheckBox("至今") self.edu_gpa_edit = self.create_line_edit("??", "GPA") self.edu_description = QTextEdit() # 設(shè)置日期控件 self.edu_start_date.setCalendarPopup(True) self.edu_end_date.setCalendarPopup(True) self.edu_current.stateChanged.connect(self.toggle_edu_end_date) # 添加到表單 form_layout.addRow("學校:", self.edu_school_edit) form_layout.addRow("學位:", self.edu_degree_edit) form_layout.addRow("專業(yè):", self.edu_field_edit) form_layout.addRow("開始日期:", self.edu_start_date) form_layout.addRow("結(jié)束日期:", self.edu_end_date) form_layout.addRow(self.edu_current) form_layout.addRow("GPA:", self.edu_gpa_edit) form_layout.addRow("描述:", self.edu_description) # 按鈕布局 btn_layout = QHBoxLayout() self.add_edu_btn = self.create_button("? 添加", "#4CAF50") self.add_edu_btn.clicked.connect(self.add_education) self.update_edu_btn = self.create_button("?? 更新", "#2196F3") self.update_edu_btn.clicked.connect(self.update_education) self.remove_edu_btn = self.create_button("? 刪除", "#F44336") self.remove_edu_btn.clicked.connect(self.remove_education) btn_layout.addWidget(self.add_edu_btn) btn_layout.addWidget(self.update_edu_btn) btn_layout.addWidget(self.remove_edu_btn) # 教育經(jīng)歷列表組 list_group = QGroupBox("教育經(jīng)歷列表") list_layout = QVBoxLayout() list_group.setLayout(list_layout) self.edu_list = QListWidget() self.edu_list.itemClicked.connect(self.load_education) self.edu_list.setStyleSheet(""" QListWidget { font-size: 14px; } QListWidget::item { padding: 8px; border-bottom: 1px solid #eee; } QListWidget::item:hover { background-color: #f0f0f0; } QListWidget::item:selected { background-color: #e3f2fd; color: #000; } """) list_layout.addWidget(self.edu_list) # 添加到主布局 layout.addWidget(form_group) layout.addLayout(btn_layout) layout.addWidget(list_group) self.left_panel.addTab(tab, "教育經(jīng)歷") def create_button(self, text, color): """創(chuàng)建帶樣式的按鈕""" btn = QPushButton(text) btn.setStyleSheet(f""" QPushButton {{ background-color: {color}; color: white; padding: 8px 12px; border-radius: 4px; font-weight: bold; }} QPushButton:hover {{ background-color: {self.darken_color(color)}; }} """) return btn def darken_color(self, hex_color, factor=0.8): """使顏色變暗""" color = QColor(hex_color) return color.darker(int(1/factor*100)).name() def add_experience_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) form_group = QGroupBox("添加/編輯工作經(jīng)歷") form_layout = QFormLayout() form_group.setLayout(form_layout) self.exp_company_edit = self.create_line_edit("??", "公司名稱") self.exp_position_edit = self.create_line_edit("??", "職位") self.exp_start_date = QDateEdit() self.exp_end_date = QDateEdit() self.exp_current = QCheckBox("至今") self.exp_description = QTextEdit() self.exp_start_date.setCalendarPopup(True) self.exp_end_date.setCalendarPopup(True) self.exp_current.stateChanged.connect(self.toggle_exp_end_date) form_layout.addRow("公司:", self.exp_company_edit) form_layout.addRow("職位:", self.exp_position_edit) form_layout.addRow("開始日期:", self.exp_start_date) form_layout.addRow("結(jié)束日期:", self.exp_end_date) form_layout.addRow(self.exp_current) form_layout.addRow("描述:", self.exp_description) btn_layout = QHBoxLayout() self.add_exp_btn = self.create_button("? 添加", "#4CAF50") self.add_exp_btn.clicked.connect(self.add_experience) self.update_exp_btn = self.create_button("?? 更新", "#2196F3") self.update_exp_btn.clicked.connect(self.update_experience) self.remove_exp_btn = self.create_button("? 刪除", "#F44336") self.remove_exp_btn.clicked.connect(self.remove_experience) btn_layout.addWidget(self.add_exp_btn) btn_layout.addWidget(self.update_exp_btn) btn_layout.addWidget(self.remove_exp_btn) list_group = QGroupBox("工作經(jīng)歷列表") list_layout = QVBoxLayout() list_group.setLayout(list_layout) self.exp_list = QListWidget() self.exp_list.itemClicked.connect(self.load_experience) list_layout.addWidget(self.exp_list) layout.addWidget(form_group) layout.addLayout(btn_layout) layout.addWidget(list_group) self.left_panel.addTab(tab, "工作經(jīng)歷") def add_skills_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) form_group = QGroupBox("添加技能") form_layout = QVBoxLayout() form_group.setLayout(form_layout) skill_layout = QHBoxLayout() self.skill_edit = self.create_line_edit("??", "技能名稱") self.skill_level_combo = QComboBox() self.skill_level_combo.addItems(["初級", "中級", "高級", "專家"]) skill_layout.addWidget(self.skill_edit) skill_layout.addWidget(self.skill_level_combo) btn_layout = QHBoxLayout() self.add_skill_btn = self.create_button("? 添加技能", "#4CAF50") self.add_skill_btn.clicked.connect(self.add_skill) self.remove_skill_btn = self.create_button("? 刪除選中", "#F44336") self.remove_skill_btn.clicked.connect(self.remove_skill) btn_layout.addWidget(self.add_skill_btn) btn_layout.addWidget(self.remove_skill_btn) list_group = QGroupBox("技能列表") list_layout = QVBoxLayout() list_group.setLayout(list_layout) self.skill_list = QListWidget() list_layout.addWidget(self.skill_list) form_layout.addWidget(QLabel("添加技能:")) form_layout.addLayout(skill_layout) form_layout.addLayout(btn_layout) layout.addWidget(form_group) layout.addWidget(list_group) self.left_panel.addTab(tab, "技能") def add_projects_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) form_group = QGroupBox("添加/編輯項目") form_layout = QFormLayout() form_group.setLayout(form_layout) self.proj_name_edit = self.create_line_edit("??", "項目名稱") self.proj_role_edit = self.create_line_edit("??", "你的角色") self.proj_start_date = QDateEdit() self.proj_end_date = QDateEdit() self.proj_current = QCheckBox("進行中") self.proj_description = QTextEdit() self.proj_url_edit = self.create_line_edit("??", "項目URL") self.proj_start_date.setCalendarPopup(True) self.proj_end_date.setCalendarPopup(True) self.proj_current.stateChanged.connect(self.toggle_proj_end_date) form_layout.addRow("項目名稱:", self.proj_name_edit) form_layout.addRow("你的角色:", self.proj_role_edit) form_layout.addRow("開始日期:", self.proj_start_date) form_layout.addRow("結(jié)束日期:", self.proj_end_date) form_layout.addRow(self.proj_current) form_layout.addRow("項目URL:", self.proj_url_edit) form_layout.addRow("描述:", self.proj_description) btn_layout = QHBoxLayout() self.add_proj_btn = self.create_button("? 添加", "#4CAF50") self.add_proj_btn.clicked.connect(self.add_project) self.update_proj_btn = self.create_button("?? 更新", "#2196F3") self.update_proj_btn.clicked.connect(self.update_project) self.remove_proj_btn = self.create_button("? 刪除", "#F44336") self.remove_proj_btn.clicked.connect(self.remove_project) btn_layout.addWidget(self.add_proj_btn) btn_layout.addWidget(self.update_proj_btn) btn_layout.addWidget(self.remove_proj_btn) list_group = QGroupBox("項目列表") list_layout = QVBoxLayout() list_group.setLayout(list_layout) self.proj_list = QListWidget() self.proj_list.itemClicked.connect(self.load_project) list_layout.addWidget(self.proj_list) layout.addWidget(form_group) layout.addLayout(btn_layout) layout.addWidget(list_group) self.left_panel.addTab(tab, "項目經(jīng)歷") def add_certifications_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) form_group = QGroupBox("添加/編輯證書") form_layout = QFormLayout() form_group.setLayout(form_layout) self.cert_name_edit = self.create_line_edit("??", "證書名稱") self.cert_org_edit = self.create_line_edit("???", "頒發(fā)機構(gòu)") self.cert_date = QDateEdit() self.cert_url_edit = self.create_line_edit("??", "證書URL") self.cert_date.setCalendarPopup(True) form_layout.addRow("證書名稱:", self.cert_name_edit) form_layout.addRow("頒發(fā)機構(gòu):", self.cert_org_edit) form_layout.addRow("獲得日期:", self.cert_date) form_layout.addRow("證書URL:", self.cert_url_edit) btn_layout = QHBoxLayout() self.add_cert_btn = self.create_button("? 添加", "#4CAF50") self.add_cert_btn.clicked.connect(self.add_certification) self.update_cert_btn = self.create_button("?? 更新", "#2196F3") self.update_cert_btn.clicked.connect(self.update_certification) self.remove_cert_btn = self.create_button("? 刪除", "#F44336") self.remove_cert_btn.clicked.connect(self.remove_certification) btn_layout.addWidget(self.add_cert_btn) btn_layout.addWidget(self.update_cert_btn) btn_layout.addWidget(self.remove_cert_btn) list_group = QGroupBox("證書列表") list_layout = QVBoxLayout() list_group.setLayout(list_layout) self.cert_list = QListWidget() self.cert_list.itemClicked.connect(self.load_certification) list_layout.addWidget(self.cert_list) layout.addWidget(form_group) layout.addLayout(btn_layout) layout.addWidget(list_group) self.left_panel.addTab(tab, "證書") def add_languages_tab(self): tab = QWidget() layout = QVBoxLayout() tab.setLayout(layout) form_group = QGroupBox("添加語言") form_layout = QVBoxLayout() form_group.setLayout(form_layout) lang_layout = QHBoxLayout() self.lang_edit = self.create_line_edit("??", "語言") self.lang_level_combo = QComboBox() self.lang_level_combo.addItems(["初級", "中級", "高級", "母語"]) lang_layout.addWidget(self.lang_edit) lang_layout.addWidget(self.lang_level_combo) btn_layout = QHBoxLayout() self.add_lang_btn = self.create_button("? 添加語言", "#4CAF50") self.add_lang_btn.clicked.connect(self.add_language) self.remove_lang_btn = self.create_button("? 刪除選中", "#F44336") self.remove_lang_btn.clicked.connect(self.remove_language) btn_layout.addWidget(self.add_lang_btn) btn_layout.addWidget(self.remove_lang_btn) list_group = QGroupBox("語言列表") list_layout = QVBoxLayout() list_group.setLayout(list_layout) self.lang_list = QListWidget() list_layout.addWidget(self.lang_list) form_layout.addWidget(QLabel("添加語言:")) form_layout.addLayout(lang_layout) form_layout.addLayout(btn_layout) layout.addWidget(form_group) layout.addWidget(list_group) self.left_panel.addTab(tab, "語言能力") def toggle_edu_end_date(self, state): self.edu_end_date.setEnabled(not bool(state)) def toggle_exp_end_date(self, state): self.exp_end_date.setEnabled(not bool(state)) def toggle_proj_end_date(self, state): self.proj_end_date.setEnabled(not bool(state)) def load_templates(self): """加載簡歷模板""" templates = [ "?? 多彩創(chuàng)意模板", "?? 專業(yè)商務(wù)模板", "?? 傳統(tǒng)經(jīng)典模板", "?? 現(xiàn)代簡約模板", "?? 數(shù)據(jù)分析師模板", "?? 開發(fā)者模板", "?? 學術(shù)模板", "?? 設(shè)計師模板" ] self.template_combo.addItems(templates) def collect_personal_info(self): self.resume_data["personal_info"] = { "name": self.name_edit.text(), "email": self.email_edit.text(), "phone": self.phone_edit.text(), "address": self.address_edit.text(), "linkedin": self.linkedin_edit.text(), "github": self.github_edit.text(), "website": self.website_edit.text() } def collect_summary(self): self.resume_data["summary"] = self.summary_edit.toPlainText() def add_education(self): self.collect_personal_info() edu = { "school": self.edu_school_edit.text(), "degree": self.edu_degree_edit.text(), "field": self.edu_field_edit.text(), "start_date": self.edu_start_date.date().toString("yyyy-MM-dd"), "end_date": "" if self.edu_current.isChecked() else self.edu_end_date.date().toString("yyyy-MM-dd"), "current": self.edu_current.isChecked(), "gpa": self.edu_gpa_edit.text(), "description": self.edu_description.toPlainText() } self.resume_data["education"].append(edu) self.update_education_list() self.clear_education_form() def update_education(self): if self.current_edu_index == -1: return edu = { "school": self.edu_school_edit.text(), "degree": self.edu_degree_edit.text(), "field": self.edu_field_edit.text(), "start_date": self.edu_start_date.date().toString("yyyy-MM-dd"), "end_date": "" if self.edu_current.isChecked() else self.edu_end_date.date().toString("yyyy-MM-dd"), "current": self.edu_current.isChecked(), "gpa": self.edu_gpa_edit.text(), "description": self.edu_description.toPlainText() } self.resume_data["education"][self.current_edu_index] = edu self.update_education_list() self.clear_education_form() self.current_edu_index = -1 def remove_education(self): if self.current_edu_index == -1: return self.resume_data["education"].pop(self.current_edu_index) self.update_education_list() self.clear_education_form() self.current_edu_index = -1 def load_education(self, item): index = self.edu_list.row(item) self.current_edu_index = index edu = self.resume_data["education"][index] self.edu_school_edit.setText(edu["school"]) self.edu_degree_edit.setText(edu["degree"]) self.edu_field_edit.setText(edu["field"]) self.edu_start_date.setDate(QDate.fromString(edu["start_date"], "yyyy-MM-dd")) if edu["current"]: self.edu_current.setChecked(True) self.edu_end_date.setEnabled(False) else: self.edu_current.setChecked(False) self.edu_end_date.setDate(QDate.fromString(edu["end_date"], "yyyy-MM-dd")) self.edu_end_date.setEnabled(True) self.edu_gpa_edit.setText(edu["gpa"]) self.edu_description.setPlainText(edu["description"]) def update_education_list(self): self.edu_list.clear() for edu in self.resume_data["education"]: item = QListWidgetItem(f"{edu['degree']} - {edu['school']}") self.edu_list.addItem(item) def clear_education_form(self): self.edu_school_edit.clear() self.edu_degree_edit.clear() self.edu_field_edit.clear() self.edu_start_date.setDate(QDate.currentDate()) self.edu_end_date.setDate(QDate.currentDate()) self.edu_current.setChecked(False) self.edu_gpa_edit.clear() self.edu_description.clear() self.edu_end_date.setEnabled(True) def add_experience(self): self.collect_personal_info() exp = { "company": self.exp_company_edit.text(), "position": self.exp_position_edit.text(), "start_date": self.exp_start_date.date().toString("yyyy-MM-dd"), "end_date": "" if self.exp_current.isChecked() else self.exp_end_date.date().toString("yyyy-MM-dd"), "current": self.exp_current.isChecked(), "description": self.exp_description.toPlainText() } self.resume_data["experience"].append(exp) self.update_experience_list() self.clear_experience_form() def update_experience(self): if self.current_exp_index == -1: return exp = { "company": self.exp_company_edit.text(), "position": self.exp_position_edit.text(), "start_date": self.exp_start_date.date().toString("yyyy-MM-dd"), "end_date": "" if self.exp_current.isChecked() else self.exp_end_date.date().toString("yyyy-MM-dd"), "current": self.exp_current.isChecked(), "description": self.exp_description.toPlainText() } self.resume_data["experience"][self.current_exp_index] = exp self.update_experience_list() self.clear_experience_form() self.current_exp_index = -1 def remove_experience(self): if self.current_exp_index == -1: return self.resume_data["experience"].pop(self.current_exp_index) self.update_experience_list() self.clear_experience_form() self.current_exp_index = -1 def load_experience(self, item): index = self.exp_list.row(item) self.current_exp_index = index exp = self.resume_data["experience"][index] self.exp_company_edit.setText(exp["company"]) self.exp_position_edit.setText(exp["position"]) self.exp_start_date.setDate(QDate.fromString(exp["start_date"], "yyyy-MM-dd")) if exp["current"]: self.exp_current.setChecked(True) self.exp_end_date.setEnabled(False) else: self.exp_current.setChecked(False) self.exp_end_date.setDate(QDate.fromString(exp["end_date"], "yyyy-MM-dd")) self.exp_end_date.setEnabled(True) self.exp_description.setPlainText(exp["description"]) def update_experience_list(self): self.exp_list.clear() for exp in self.resume_data["experience"]: item = QListWidgetItem(f"{exp['position']} - {exp['company']}") self.exp_list.addItem(item) def clear_experience_form(self): self.exp_company_edit.clear() self.exp_position_edit.clear() self.exp_start_date.setDate(QDate.currentDate()) self.exp_end_date.setDate(QDate.currentDate()) self.exp_current.setChecked(False) self.exp_description.clear() self.exp_end_date.setEnabled(True) def add_skill(self): skill = f"{self.skill_edit.text()} ({self.skill_level_combo.currentText()})" self.resume_data["skills"].append(skill) self.update_skills_list() self.skill_edit.clear() def remove_skill(self): for item in self.skill_list.selectedItems(): index = self.skill_list.row(item) self.resume_data["skills"].pop(index) self.skill_list.takeItem(index) def update_skills_list(self): self.skill_list.clear() for skill in self.resume_data["skills"]: self.skill_list.addItem(skill) def add_project(self): self.collect_personal_info() proj = { "name": self.proj_name_edit.text(), "role": self.proj_role_edit.text(), "start_date": self.proj_start_date.date().toString("yyyy-MM-dd"), "end_date": "" if self.proj_current.isChecked() else self.proj_end_date.date().toString("yyyy-MM-dd"), "current": self.proj_current.isChecked(), "url": self.proj_url_edit.text(), "description": self.proj_description.toPlainText() } self.resume_data["projects"].append(proj) self.update_project_list() self.clear_project_form() def update_project(self): if self.current_proj_index == -1: return proj = { "name": self.proj_name_edit.text(), "role": self.proj_role_edit.text(), "start_date": self.proj_start_date.date().toString("yyyy-MM-dd"), "end_date": "" if self.proj_current.isChecked() else self.proj_end_date.date().toString("yyyy-MM-dd"), "current": self.proj_current.isChecked(), "url": self.proj_url_edit.text(), "description": self.proj_description.toPlainText() } self.resume_data["projects"][self.current_proj_index] = proj self.update_project_list() self.clear_project_form() self.current_proj_index = -1 def remove_project(self): if self.current_proj_index == -1: return self.resume_data["projects"].pop(self.current_proj_index) self.update_project_list() self.clear_project_form() self.current_proj_index = -1 def load_project(self, item): index = self.proj_list.row(item) self.current_proj_index = index proj = self.resume_data["projects"][index] self.proj_name_edit.setText(proj["name"]) self.proj_role_edit.setText(proj["role"]) self.proj_start_date.setDate(QDate.fromString(proj["start_date"], "yyyy-MM-dd")) if proj["current"]: self.proj_current.setChecked(True) self.proj_end_date.setEnabled(False) else: self.proj_current.setChecked(False) self.proj_end_date.setDate(QDate.fromString(proj["end_date"], "yyyy-MM-dd")) self.proj_end_date.setEnabled(True) self.proj_url_edit.setText(proj["url"]) self.proj_description.setPlainText(proj["description"]) def update_project_list(self): self.proj_list.clear() for proj in self.resume_data["projects"]: item = QListWidgetItem(f"{proj['name']} ({proj['role']})") self.proj_list.addItem(item) def clear_project_form(self): self.proj_name_edit.clear() self.proj_role_edit.clear() self.proj_start_date.setDate(QDate.currentDate()) self.proj_end_date.setDate(QDate.currentDate()) self.proj_current.setChecked(False) self.proj_url_edit.clear() self.proj_description.clear() self.proj_end_date.setEnabled(True) def add_certification(self): self.collect_personal_info() cert = { "name": self.cert_name_edit.text(), "organization": self.cert_org_edit.text(), "date": self.cert_date.date().toString("yyyy-MM-dd"), "url": self.cert_url_edit.text() } self.resume_data["certifications"].append(cert) self.update_certification_list() self.clear_certification_form() def update_certification(self): if self.current_cert_index == -1: return cert = { "name": self.cert_name_edit.text(), "organization": self.cert_org_edit.text(), "date": self.cert_date.date().toString("yyyy-MM-dd"), "url": self.cert_url_edit.text() } self.resume_data["certifications"][self.current_cert_index] = cert self.update_certification_list() self.clear_certification_form() self.current_cert_index = -1 def remove_certification(self): if self.current_cert_index == -1: return self.resume_data["certifications"].pop(self.current_cert_index) self.update_certification_list() self.clear_certification_form() self.current_cert_index = -1 def load_certification(self, item): index = self.cert_list.row(item) self.current_cert_index = index cert = self.resume_data["certifications"][index] self.cert_name_edit.setText(cert["name"]) self.cert_org_edit.setText(cert["organization"]) self.cert_date.setDate(QDate.fromString(cert["date"], "yyyy-MM-dd")) self.cert_url_edit.setText(cert["url"]) def update_certification_list(self): self.cert_list.clear() for cert in self.resume_data["certifications"]: item = QListWidgetItem(f"{cert['name']} - {cert['organization']}") self.cert_list.addItem(item) def clear_certification_form(self): self.cert_name_edit.clear() self.cert_org_edit.clear() self.cert_date.setDate(QDate.currentDate()) self.cert_url_edit.clear() def add_language(self): lang = f"{self.lang_edit.text()} ({self.lang_level_combo.currentText()})" self.resume_data["languages"].append(lang) self.update_languages_list() self.lang_edit.clear() def remove_language(self): for item in self.lang_list.selectedItems(): index = self.lang_list.row(item) self.resume_data["languages"].pop(index) self.lang_list.takeItem(index) def update_languages_list(self): self.lang_list.clear() for lang in self.resume_data["languages"]: self.lang_list.addItem(lang) def preview_resume(self): """生成簡歷預(yù)覽""" self.collect_personal_info() self.collect_summary() preview_text = "=== 簡歷預(yù)覽 ===\n\n" preview_text += "?? 個人信息:\n" preview_text += f"?? 姓名: {self.resume_data['personal_info']['name']}\n" preview_text += f"?? 郵箱: {self.resume_data['personal_info']['email']}\n" preview_text += f"?? 電話: {self.resume_data['personal_info']['phone']}\n" preview_text += f"?? 地址: {self.resume_data['personal_info']['address']}\n" preview_text += f"?? LinkedIn: {self.resume_data['personal_info']['linkedin']}\n" preview_text += f"?? GitHub: {self.resume_data['personal_info']['github']}\n" preview_text += f"?? 個人網(wǎng)站: {self.resume_data['personal_info']['website']}\n\n" preview_text += "?? 職業(yè)概述:\n" preview_text += f"{self.resume_data['summary']}\n\n" preview_text += "?? 教育經(jīng)歷:\n" for edu in self.resume_data["education"]: preview_text += f"- ?? {edu['degree']} - {edu['school']} ({edu['field']})\n" preview_text += f" ?? {edu['start_date']} 至 {'至今' if edu['current'] else edu['end_date']}\n" preview_text += f" ?? GPA: {edu['gpa']}\n" preview_text += f" ?? 描述: {edu['description']}\n\n" preview_text += "?? 工作經(jīng)歷:\n" for exp in self.resume_data["experience"]: preview_text += f"- ?? {exp['position']} - {exp['company']}\n" preview_text += f" ?? {exp['start_date']} 至 {'至今' if exp['current'] else exp['end_date']}\n" preview_text += f" ?? 描述: {exp['description']}\n\n" preview_text += "??? 技能:\n" for skill in self.resume_data["skills"]: preview_text += f"- {skill}\n" preview_text += "\n" preview_text += "?? 項目經(jīng)歷:\n" for proj in self.resume_data["projects"]: preview_text += f"- ?? {proj['name']} ({proj['role']})\n" preview_text += f" ?? {proj['start_date']} 至 {'進行中' if proj['current'] else proj['end_date']}\n" preview_text += f" ?? URL: {proj['url']}\n" preview_text += f" ?? 描述: {proj['description']}\n\n" preview_text += "?? 證書:\n" for cert in self.resume_data["certifications"]: preview_text += f"- ?? {cert['name']} - {cert['organization']} ({cert['date']})\n" preview_text += f" ?? URL: {cert['url']}\n\n" preview_text += "?? 語言能力:\n" for lang in self.resume_data["languages"]: preview_text += f"- {lang}\n" self.preview_text.setPlainText(preview_text) def export_to_pdf(self): self.collect_personal_info() self.collect_summary() # 創(chuàng)建PDF pdf = FPDF() pdf.add_page() pdf.set_auto_page_break(auto=True, margin=15) # 設(shè)置字體 pdf.set_font("Arial", 'B', 16) # 個人信息 pdf.cell(0, 10, self.resume_data["personal_info"]["name"], 0, 1, 'C') pdf.set_font("Arial", '', 12) contact_info = [] if self.resume_data["personal_info"]["email"]: contact_info.append(self.resume_data["personal_info"]["email"]) if self.resume_data["personal_info"]["phone"]: contact_info.append(self.resume_data["personal_info"]["phone"]) if self.resume_data["personal_info"]["address"]: contact_info.append(self.resume_data["personal_info"]["address"]) pdf.cell(0, 10, " | ".join(contact_info), 0, 1, 'C') # 添加鏈接 links = [] if self.resume_data["personal_info"]["linkedin"]: links.append(f"LinkedIn: {self.resume_data['personal_info']['linkedin']}") if self.resume_data["personal_info"]["github"]: links.append(f"GitHub: {self.resume_data['personal_info']['github']}") if self.resume_data["personal_info"]["website"]: links.append(f"Website: {self.resume_data['personal_info']['website']}") if links: pdf.cell(0, 10, " | ".join(links), 0, 1, 'C') pdf.ln(10) # 職業(yè)概述 if self.resume_data["summary"]: pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, "職業(yè)概述", 0, 1, 'L') pdf.set_font("Arial", '', 12) pdf.multi_cell(0, 6, self.resume_data["summary"]) pdf.ln(5) # 教育經(jīng)歷 if self.resume_data["education"]: pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, "教育經(jīng)歷", 0, 1, 'L') pdf.set_font("Arial", '', 12) for edu in self.resume_data["education"]: pdf.set_font("Arial", 'B', 12) pdf.cell(0, 6, f"{edu['degree']} - {edu['school']}", 0, 1, 'L') pdf.set_font("Arial", '', 12) date_range = f"{edu['start_date']} - {'至今' if edu['current'] else edu['end_date']}" if edu["gpa"]: date_range += f" | GPA: {edu['gpa']}" pdf.cell(0, 6, f"{edu['field']} | {date_range}", 0, 1, 'L') if edu["description"]: pdf.multi_cell(0, 6, edu["description"]) pdf.ln(2) # 工作經(jīng)歷 if self.resume_data["experience"]: pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, "工作經(jīng)歷", 0, 1, 'L') pdf.set_font("Arial", '', 12) for exp in self.resume_data["experience"]: pdf.set_font("Arial", 'B', 12) pdf.cell(0, 6, f"{exp['position']} - {exp['company']}", 0, 1, 'L') pdf.set_font("Arial", '', 12) pdf.cell(0, 6, f"{exp['start_date']} - {'至今' if exp['current'] else exp['end_date']}", 0, 1, 'L') if exp["description"]: pdf.multi_cell(0, 6, exp["description"]) pdf.ln(2) # 技能 if self.resume_data["skills"]: pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, "技能", 0, 1, 'L') pdf.set_font("Arial", '', 12) skills = ", ".join(self.resume_data["skills"]) pdf.multi_cell(0, 6, skills) pdf.ln(5) # 項目經(jīng)歷 if self.resume_data["projects"]: pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, "項目經(jīng)歷", 0, 1, 'L') pdf.set_font("Arial", '', 12) for proj in self.resume_data["projects"]: pdf.set_font("Arial", 'B', 12) pdf.cell(0, 6, f"{proj['name']} ({proj['role']})", 0, 1, 'L') pdf.set_font("Arial", '', 12) date_range = f"{proj['start_date']} - {'進行中' if proj['current'] else proj['end_date']}" if proj["url"]: date_range += f" | URL: {proj['url']}" pdf.cell(0, 6, date_range, 0, 1, 'L') if proj["description"]: pdf.multi_cell(0, 6, proj["description"]) pdf.ln(2) # 證書 if self.resume_data["certifications"]: pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, "證書", 0, 1, 'L') pdf.set_font("Arial", '', 12) for cert in self.resume_data["certifications"]: cert_line = f"{cert['name']} - {cert['organization']} ({cert['date']})" if cert["url"]: cert_line += f" | URL: {cert['url']}" pdf.cell(0, 6, cert_line, 0, 1, 'L') pdf.ln(2) # 語言能力 if self.resume_data["languages"]: pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, "語言能力", 0, 1, 'L') pdf.set_font("Arial", '', 12) langs = ", ".join(self.resume_data["languages"]) pdf.multi_cell(0, 6, langs) # 保存PDF file_path, _ = QFileDialog.getSaveFileName(self, "保存PDF", "我的簡歷.pdf", "PDF文件 (*.pdf)") if file_path: pdf.output(file_path) QMessageBox.information(self, "成功", "簡歷已成功導出為PDF!") def save_resume_data(self): self.collect_personal_info() self.collect_summary() file_path, _ = QFileDialog.getSaveFileName(self, "保存簡歷數(shù)據(jù)", "resume_data.json", "JSON文件 (*.json)") if file_path: with open(file_path, 'w', encoding='utf-8') as f: json.dump(self.resume_data, f, ensure_ascii=False, indent=4) QMessageBox.information(self, "成功", "簡歷數(shù)據(jù)已保存!") def load_resume_data(self): file_path, _ = QFileDialog.getOpenFileName(self, "加載簡歷數(shù)據(jù)", "", "JSON文件 (*.json)") if file_path: try: with open(file_path, 'r', encoding='utf-8') as f: self.resume_data = json.load(f) # 更新UI self.update_ui_from_data() QMessageBox.information(self, "成功", "簡歷數(shù)據(jù)已加載!") except Exception as e: QMessageBox.critical(self, "錯誤", f"加載簡歷數(shù)據(jù)失敗: {str(e)}") def update_ui_from_data(self): # 個人信息 personal_info = self.resume_data["personal_info"] self.name_edit.setText(personal_info.get("name", "")) self.email_edit.setText(personal_info.get("email", "")) self.phone_edit.setText(personal_info.get("phone", "")) self.address_edit.setText(personal_info.get("address", "")) self.linkedin_edit.setText(personal_info.get("linkedin", "")) self.github_edit.setText(personal_info.get("github", "")) self.website_edit.setText(personal_info.get("website", "")) # 職業(yè)概述 self.summary_edit.setPlainText(self.resume_data.get("summary", "")) # 教育經(jīng)歷 self.update_education_list() # 工作經(jīng)歷 self.update_experience_list() # 技能 self.update_skills_list() # 項目經(jīng)歷 self.update_project_list() # 證書 self.update_certification_list() # 語言能力 self.update_languages_list() if __name__ == "__main__": app = QApplication(sys.argv) # 設(shè)置應(yīng)用程序樣式和字體 app.setStyle("Fusion") # 設(shè)置調(diào)色板 palette = QPalette() palette.setColor(QPalette.Window, QColor(240, 242, 245)) palette.setColor(QPalette.WindowText, QColor(0, 0, 0)) palette.setColor(QPalette.Base, QColor(255, 255, 255)) palette.setColor(QPalette.AlternateBase, QColor(240, 240, 240)) palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 255)) palette.setColor(QPalette.ToolTipText, QColor(0, 0, 0)) palette.setColor(QPalette.Text, QColor(0, 0, 0)) palette.setColor(QPalette.Button, QColor(240, 240, 240)) palette.setColor(QPalette.ButtonText, QColor(0, 0, 0)) palette.setColor(QPalette.BrightText, QColor(255, 0, 0)) palette.setColor(QPalette.Highlight, QColor(76, 175, 80)) palette.setColor(QPalette.HighlightedText, QColor(255, 255, 255)) app.setPalette(palette) # 創(chuàng)建并顯示主窗口 window = ResumeGenerator() window.show() sys.exit(app.exec_())
七、總結(jié)與展望
本工具通過PyQt5實現(xiàn)了:
- 高效管理:比傳統(tǒng)文檔編輯效率提升300%
- 專業(yè)輸出:符合HR系統(tǒng)的解析標準
- 靈活定制:模塊化設(shè)計易于擴展
未來可增加:
- LaTeX導出支持
- 在線模板市場
- AI輔助內(nèi)容生成
- 多語言國際化
Q&A環(huán)節(jié)
Q:如何添加自定義模板?
A:在templates目錄下新建JSON文件,按照現(xiàn)有模板格式編寫樣式規(guī)則。
Q:程序無法顯示中文怎么辦?
A:確保系統(tǒng)已安裝中文字體,并在PDF生成時指定中文字體路徑。
Q:能否導出為Word格式?
A:當前版本僅支持PDF,可通過python-docx庫自行擴展。
相關(guān)技術(shù)棧推薦
- 高級功能:PyQtGraph數(shù)據(jù)可視化
- 云存儲:集成Dropbox API
- 自動化:結(jié)合Selenium實現(xiàn)自動投遞
求職小貼士
使用本工具生成簡歷后,建議:
- 根據(jù)不同崗位調(diào)整關(guān)鍵詞
- 保持一頁紙原則
- 量化工作成果
- 定期更新內(nèi)容
到此這篇關(guān)于Python+PyQt5實現(xiàn)簡歷自動生成工具的文章就介紹到這了,更多相關(guān)Python自動生成簡歷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實現(xiàn)繁體中文與簡體中文相互轉(zhuǎn)換的方法示例
這篇文章主要介紹了Python實現(xiàn)繁體中文與簡體中文相互轉(zhuǎn)換的方法,涉及Python基于第三方模塊進行編碼轉(zhuǎn)換相關(guān)操作技巧,需要的朋友可以參考下2018-12-12python框架django中結(jié)合vue進行前后端分離
本篇將基于Python+Django結(jié)合Vue.js前端框架,為大家介紹如何基于這三者的技術(shù)棧來實現(xiàn)一個前端后離的Web開發(fā)項目。文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01python 如何把classification_report輸出到csv文件
這篇文章主要介紹了python 把classification_report輸出到csv文件的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-05-05PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解
今天小編就為大家分享一篇PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01Python解決asyncio文件描述符最大數(shù)量限制的問題
這篇文章主要介紹了Python解決asyncio文件描述符最大數(shù)量限制的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06