diff --git a/borax/__init__.py b/borax/__init__.py index c3df011..86ad3c7 100644 --- a/borax/__init__.py +++ b/borax/__init__.py @@ -1,2 +1,2 @@ -__version__ = '4.1.0' +__version__ = '4.1.1' __author__ = 'kinegratii' diff --git a/borax/calendars/festivals2.py b/borax/calendars/festivals2.py index e402ab5..6ef87eb 100644 --- a/borax/calendars/festivals2.py +++ b/borax/calendars/festivals2.py @@ -30,6 +30,8 @@ class FreqConst: YEARLY = 0 MONTHLY = 1 + LABEL2VAL = {'monthly': 1, 'yearly': 0, 'm': 1, 'y': 0} + class FestivalCatalog: basic = 'basic' @@ -167,8 +169,9 @@ class Period: """A shortcut methods for some specified date Period.""" @staticmethod - def solar_year(year: int) -> Tuple[date, date]: - return date(year, 1, 1), date(year, 12, 31) + def solar_year(year: int, end_year: int = 0) -> Tuple[date, date]: + end_year = end_year or year + return date(year, 1, 1), date(end_year, 12, 31) @staticmethod def solar_month(year: int, month: int) -> Tuple[date, date]: @@ -176,8 +179,9 @@ def solar_month(year: int, month: int) -> Tuple[date, date]: return date(year, month, 1), date(year, month, ndays) @staticmethod - def lunar_year(year: int) -> Tuple[LunarDate, LunarDate]: - return LunarDate(year, 1, 1), LunarDate(year + 1, 1, 1) - timedelta(days=1) + def lunar_year(year: int, end_year: int = 0) -> Tuple[LunarDate, LunarDate]: + end_year = end_year or year + return LunarDate(year, 1, 1), LunarDate.last_day(end_year) @staticmethod def lunar_month(year: int, month: int, leap: int = _IGNORE_LEAP_MONTH) -> Tuple[LunarDate, LunarDate]: @@ -460,12 +464,17 @@ class SolarFestival(Festival): """ date_class = date - def __init__(self, *, day: int, freq: int = FreqConst.YEARLY, month: int = 0, name: str = None): + def __init__(self, *, day: int, freq: Union[int, Literal['yearly', 'monthly', 'y', 'm']] = FreqConst.YEARLY, + month: int = 0, name: str = None): if day < 0: day = -day reverse = 1 else: reverse = 0 + if isinstance(freq, str): + freq = FreqConst.LABEL2VAL.get(freq, -1) + if freq == -1: + raise ValueError('Invalid freq string.') super().__init__(name=name, freq=freq, month=month, day=day, reverse=reverse, schema=FestivalSchema.SOLAR) def _get_description(self) -> str: @@ -680,13 +689,17 @@ class LunarFestival(Festival): """ date_class = LunarDate - def __init__(self, *, day: int, freq: int = FreqConst.YEARLY, month: int = 0, leap: int = _IGNORE_LEAP_MONTH, - name: str = None): + def __init__(self, *, day: int, freq: Union[int, Literal['yearly', 'monthly', 'y', 'm']] = FreqConst.YEARLY, + month: int = 0, leap: int = _IGNORE_LEAP_MONTH, name: str = None): if day < 0: day = -day reverse = 1 else: reverse = 0 + if isinstance(freq, str): + freq = FreqConst.LABEL2VAL.get(freq, -1) + if freq == -1: + raise ValueError('Invalid freq string.') super().__init__(freq=freq, name=name, month=month, day=day, leap=leap, reverse=reverse, schema=FestivalSchema.LUNAR) diff --git a/borax/calendars/lunardate.py b/borax/calendars/lunardate.py index c00591d..aa87b03 100644 --- a/borax/calendars/lunardate.py +++ b/borax/calendars/lunardate.py @@ -658,6 +658,24 @@ def tomorrow(cls) -> 'LunarDate': sd = datetime.date.today() + datetime.timedelta(days=1) return cls.from_solar_date(sd.year, sd.month, sd.day) + @classmethod + def last_day(cls, year: int, month: int = 0, leap: int = 0) -> 'LunarDate': + """return the last day in a lunar year or a lunar month.""" + mdls = list(LCalendars.iter_year_month(year)) + if month == 0: + index = -1 + else: + leap_month_of_year = LCalendars.leap_month(year) + if leap: + if month == leap_month_of_year: + index = month + else: + raise InvalidLunarDateError(f'{year=}, {month=},leap=1 does not exist.') + else: + index = month - 1 + int(leap_month_of_year and month > leap_month_of_year) + month, day, leap = mdls[index] + return cls(year, month, day, leap) + @classmethod def strptime(cls, date_str: str, date_fmt: str) -> 'LunarDate': """Parse a LunarDate object from a whole string. @@ -678,7 +696,7 @@ def __sub__(self, other): :param other: a instance of LunarDate / date / timedelta :return: """ - if hasattr(other, 'solar'): + if hasattr(other, 'solar'): # For WrappedDate in festivals2 module return self.to_solar_date() - other.solar elif isinstance(other, LunarDate): return self.to_solar_date() - other.to_solar_date() diff --git a/borax/capp/borax_calendar_app.py b/borax/capp/borax_calendar_app.py index bc5e2fb..dc6c165 100644 --- a/borax/capp/borax_calendar_app.py +++ b/borax/capp/borax_calendar_app.py @@ -15,6 +15,7 @@ from borax.calendars.ui import CalendarFrame, FestivalTableFrame from borax.calendars.utils import ThreeNineUtils from borax.capp.festival_creator import FestivalCreatePanel +from borax.ui.widgets import MessageLabel library = FestivalLibrary.load_builtin().sort_by_countdown() @@ -82,7 +83,7 @@ def __init__(self, master=None): ttk.Button(self._tool_form_frame, text='计算', command=self.run_date_delta).grid( row=2, column=0, columnspan=4, pady=8) - self.result1_label = ttk.Label(self._tool_form_frame, text='') + self.result1_label = MessageLabel(self._tool_form_frame, text='') self.result1_label.grid(row=3, column=0, columnspan=4) notebook.add(self._tool_form_frame, text='日期间隔', padding=4) @@ -104,7 +105,7 @@ def __init__(self, master=None): delta_days_com.grid(row=2, column=2, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S) ttk.Button(deduction_frame, text='计算', command=self.run_date_deduction).grid( row=3, column=0, columnspan=4, pady=8) - self.result2_label = ttk.Label(deduction_frame, text='') + self.result2_label = MessageLabel(deduction_frame, text='') self.result2_label.grid(row=4, column=0, columnspan=4) # init self.day_delta_s.set(1) @@ -131,17 +132,17 @@ def run_date_delta(self): d1, d2 = self._data_stores['d1'].get_date(), self._data_stores['d2'].get_date() if d1 and d2: ndays = (d2.solar - d1.solar).days - self.result1_label.config(text=f'相差 {ndays} 天') + self.result1_label.show_text(text=f'相差 {ndays} 天') else: - self.result1_label.config(text='未选择日期,无法计算') + self.result1_label.show_error_splash(text='未选择日期,无法计算') def run_date_deduction(self): d3 = self._data_stores['d3'].get_date() if d3: result2 = d3 + timedelta(self.day_delta_s.get() * self.delta_days.get()) - self.result2_label.config(text=str(result2)) + self.result2_label.show_text(str(result2)) else: - self.result2_label.config(text='未选择日期,无法计算') + self.result2_label.show_error_splash(text='未选择日期,无法计算') class DateDetailFrame(ttk.LabelFrame): diff --git a/borax/capp/festival_creator.py b/borax/capp/festival_creator.py index e728f30..b62e73c 100644 --- a/borax/capp/festival_creator.py +++ b/borax/capp/festival_creator.py @@ -8,6 +8,7 @@ ) from borax.calendars.lunardate import TextUtils, TERMS_CN from borax.calendars.ui import FestivalTableFrame +from borax.ui.widgets import MessageLabel __all__ = ['FestivalCreatePanel', 'start_festival_creator'] @@ -95,11 +96,17 @@ def init(self): def _validate_f0(self): freq, month, reverse, day = self.gets('s_freq', 's_month', 's_reverse', 's_day') + _d = abs(day) + if (month == 0 and _d > 366) or _d > 31: + raise ValidateError('公历 日/天 数值范围不正确。') festival = SolarFestival(day=reverse * day, freq=freq, month=month) return festival def _validate_f1(self): freq, leap, reverse, month, day = self.gets('l_freq', 'l_leap', 'l_reverse', 'l_month', 'l_day') + _d = abs(day) + if (month == 0 and _d > 384) or _d > 30: + raise ValidateError('农历 日/天 数值范围不正确。') festival = LunarFestival(day=reverse * day, freq=freq, leap=leap, month=month) return festival @@ -114,23 +121,13 @@ def _validate_f4(self): return festival -class MessageLabel(ttk.Label): - def splash(self, text: str, timeout: int = 1000, foreground='black', **kwargs): - self.config({'text': text, 'foreground': foreground, **kwargs}) - if timeout != 0: - self.after(timeout, self._clear) - - def _clear(self): - self.config({'text': '', 'foreground': 'black'}) - - class FestivalCreatePanel(ttk.Frame): """A UI panel with festival-CRUD futures.""" def __init__(self, master=None, **kwargs): super().__init__(master, **kwargs) - lf = ttk.LabelFrame(self, labelanchor='n', text='节日管理工具') + lf = ttk.LabelFrame(self, labelanchor='n', text='节日创建工具') lf.pack(side='top', fill='x', padx=10, pady=10, expand=True) ttk.Label(lf, text=' 本工具支持创建公历型、农历型、星期型、节气型节日,并导出为csv文件。').pack( side='top', padx=5, pady=5, fill='both', expand=True) @@ -138,9 +135,6 @@ def __init__(self, master=None, **kwargs): main_frame.pack(side='top', fill='both') self._vm = VarModel() - - n_row, s_row, l_row, w_row, t_row, btn_row, msg_row = 0, 2, 4, 6, 8, 10, 11 - empty_rows = (1, 3, 5, 7, 9) ccb_w = 10 freq_choices = ((FreqConst.YEARLY, '每年'), (FreqConst.MONTHLY, '每月')) @@ -149,88 +143,92 @@ def __init__(self, master=None, **kwargs): day_reverse_choices = [(1, '正向'), (-1, '倒数')] week_choices = list(enumerate('一二三四五六日')) term_choices = list(enumerate(TERMS_CN)) - index_choices = [(i, f'第{i}个') for i in range(1, 10)] + index_choices = [(0, '当日')] + [(i, f'第{i}个') for i in range(1, 10)] index2_choices = [(i, f'第{i}个') for i in range(1, 10)] + [(-i, f'倒数第{i}个') for i in range(1, 10)] delta_choices = [(0, '当日'), (-1, '之前'), (1, '之后')] gz_day_choices = list(TextUtils.BRANCHES + TextUtils.STEMS) + # main_frame -> + frame = ttk.Frame(main_frame) frame.pack(side='left', expand=True, fill=tk.BOTH, padx=10, pady=10) - ttk.Label(frame, text='名称').grid(row=n_row, column=0) - ttk.Entry(frame, textvariable=self._vm.vars['name']).grid(row=n_row, column=1, columnspan=3, sticky='we') - ttk.Label(frame, text='分类').grid(row=n_row, column=4) - ttk.Entry(frame, textvariable=self._vm.vars['catalog']).grid(row=n_row, column=5, columnspan=3, sticky='we') + + name_ui = ttk.Frame(frame) + name_ui.pack(side='top', fill='x') + ttk.Label(name_ui, text='名称').pack(side='left') + ttk.Entry(name_ui, textvariable=self._vm.vars['name']).pack(side='left') + ttk.Label(name_ui, text='分类').pack(side='left') + ttk.Entry(name_ui, textvariable=self._vm.vars['catalog']).pack(side='left') + # Solar Festival - ttk.Radiobutton(frame, text='公历型', value=FestivalSchema.SOLAR.value, variable=self._vm.vars['schema']).grid( - row=s_row, column=0) - ChoicesCombobox(frame, choices=freq_choices, val_variable=self._vm.vars['s_freq'], width=ccb_w).grid(row=s_row, - column=1) - ChoicesCombobox(frame, choices=month_choices, val_variable=self._vm.vars['s_month'], width=ccb_w).grid( - row=s_row, column=3) - ttk.Label(frame, text='月').grid(row=s_row, column=4) - ChoicesCombobox(frame, choices=day_reverse_choices, val_variable=self._vm.vars['s_reverse'], width=ccb_w).grid( - row=s_row, column=5) - ttk.Combobox(frame, values=list(range(1, 32)), textvariable=self._vm.vars['s_day'], width=ccb_w).grid(row=s_row, - column=6) - ttk.Label(frame, text='日/天').grid(row=s_row, column=7) + s_rb = ttk.Radiobutton(frame, text='公历型', value=FestivalSchema.SOLAR.value, variable=self._vm.vars['schema']) + s_ui = ttk.LabelFrame(frame, labelwidget=s_rb, padding=5) + s_ui.pack(side='top', fill='x', expand=True, pady=10) + ChoicesCombobox(s_ui, choices=freq_choices, val_variable=self._vm.vars['s_freq'], width=ccb_w).grid(row=0, + column=1) + ChoicesCombobox(s_ui, choices=month_choices, val_variable=self._vm.vars['s_month'], width=ccb_w).grid( + row=0, column=3) + ttk.Label(s_ui, text='月 ').grid(row=0, column=4) + ChoicesCombobox(s_ui, choices=day_reverse_choices, val_variable=self._vm.vars['s_reverse'], width=ccb_w).grid( + row=0, column=5) + ttk.Combobox(s_ui, values=list(range(1, 32)), textvariable=self._vm.vars['s_day'], width=ccb_w).grid(row=0, + column=6) + ttk.Label(s_ui, text='日/天').grid(row=0, column=7) # Lunar Festival - ttk.Radiobutton(frame, text='农历型', value=FestivalSchema.LUNAR.value, variable=self._vm.vars['schema']).grid( - row=l_row, - column=0) - ChoicesCombobox(frame, choices=freq_choices, val_variable=self._vm.vars['l_freq'], width=ccb_w).grid(row=l_row, - column=1) - ChoicesCombobox(frame, choices=leap_choices, val_variable=self._vm.vars['l_leap'], width=ccb_w).grid(row=l_row, - column=2) - ChoicesCombobox(frame, choices=month_choices, val_variable=self._vm.vars['l_month'], width=ccb_w).grid( - row=l_row, column=3) - ttk.Label(frame, text='月').grid(row=l_row, column=4) - ChoicesCombobox(frame, choices=day_reverse_choices, val_variable=self._vm.vars['l_reverse'], width=ccb_w).grid( - row=l_row, column=5) - ttk.Combobox(frame, values=list(range(1, 31)), textvariable=self._vm.vars['l_day'], width=ccb_w).grid(row=l_row, - column=6) - ttk.Label(frame, text='日/天').grid(row=l_row, column=7) + l_rb = ttk.Radiobutton(frame, text='农历型', value=FestivalSchema.LUNAR.value, variable=self._vm.vars['schema']) + l_ui = ttk.LabelFrame(frame, labelwidget=l_rb, padding=5) + l_ui.pack(side='top', fill='x', expand=True, pady=10) + ChoicesCombobox(l_ui, choices=freq_choices, val_variable=self._vm.vars['l_freq'], width=ccb_w).grid(row=0, + column=1) + ChoicesCombobox(l_ui, choices=leap_choices, val_variable=self._vm.vars['l_leap'], width=ccb_w).grid(row=0, + column=2) + ChoicesCombobox(l_ui, choices=month_choices, val_variable=self._vm.vars['l_month'], width=ccb_w).grid( + row=0, column=3) + ttk.Label(l_ui, text='月 ').grid(row=0, column=4) + ChoicesCombobox(l_ui, choices=day_reverse_choices, val_variable=self._vm.vars['l_reverse'], width=ccb_w).grid( + row=0, column=5) + ttk.Combobox(l_ui, values=list(range(1, 31)), textvariable=self._vm.vars['l_day'], width=ccb_w).grid(row=0, + column=6) + ttk.Label(l_ui, text='日/天').grid(row=0, column=7) # Week Festival - ttk.Radiobutton(frame, text='星期型', value=FestivalSchema.WEEK.value, variable=self._vm.vars['schema']).grid( - row=w_row, column=0) - ttk.Label(frame, text='每年').grid(row=w_row, column=1) - ChoicesCombobox(frame, choices=month_choices, val_variable=self._vm.vars['w_month'], width=ccb_w).grid( - row=w_row, column=3) - ttk.Label(frame, text='月').grid(row=w_row, column=4) - ChoicesCombobox(frame, choices=index2_choices, val_variable=self._vm.vars['w_index'], width=ccb_w).grid( - row=w_row, column=5, columnspan=1) - ttk.Label(frame, text='星期').grid(row=w_row, column=6, columnspan=1) - ChoicesCombobox(frame, choices=week_choices, val_variable=self._vm.vars['w_week'], width=ccb_w).grid( - row=w_row, column=7, columnspan=1) + w_rb = ttk.Radiobutton(frame, text='星期型', value=FestivalSchema.WEEK.value, variable=self._vm.vars['schema']) + w_ui = ttk.LabelFrame(frame, labelwidget=w_rb, padding=5) + w_ui.pack(side='top', fill='x', expand=True, pady=10) + + ttk.Label(w_ui, text='每年 ').grid(row=0, column=1) + ChoicesCombobox(w_ui, choices=month_choices, val_variable=self._vm.vars['w_month'], width=ccb_w).grid( + row=0, column=3) + ttk.Label(w_ui, text='月 ').grid(row=0, column=4) + ChoicesCombobox(w_ui, choices=index2_choices, val_variable=self._vm.vars['w_index'], width=ccb_w).grid( + row=0, column=5, columnspan=1) + ttk.Label(w_ui, text=' 星期').grid(row=0, column=6, columnspan=1) + ChoicesCombobox(w_ui, choices=week_choices, val_variable=self._vm.vars['w_week'], width=ccb_w).grid( + row=0, column=7, columnspan=1) # Term Festival - ttk.Radiobutton(frame, text='节气型', value=FestivalSchema.TERM.value, variable=self._vm.vars['schema']).grid( - row=t_row, - column=0) - ttk.Label(frame, text='每年').grid(row=t_row, column=1) - ChoicesCombobox(frame, choices=term_choices, val_variable=self._vm.vars['t_term'], width=ccb_w).grid( - row=t_row, column=2, columnspan=1) - ttk.Label(frame, text='节气').grid(row=t_row, column=3) - ChoicesCombobox(frame, choices=delta_choices, val_variable=self._vm.vars['t_delta'], width=ccb_w).grid( - row=t_row, column=4, columnspan=1) - ChoicesCombobox(frame, choices=index_choices, val_variable=self._vm.vars['t_index'], empty_value=0, - width=ccb_w).grid(row=t_row, column=5, columnspan=1) - ttk.Combobox(frame, values=gz_day_choices, textvariable=self._vm.vars['t_day_gz'], state='readonly', + t_rb = ttk.Radiobutton(frame, text='节气型', value=FestivalSchema.TERM.value, variable=self._vm.vars['schema']) + t_ui = ttk.LabelFrame(frame, labelwidget=t_rb, padding=5) + t_ui.pack(side='top', fill='x', expand=True, pady=10) + + ttk.Label(t_ui, text='每年 ').grid(row=0, column=1) + ChoicesCombobox(t_ui, choices=term_choices, val_variable=self._vm.vars['t_term'], width=ccb_w).grid( + row=0, column=2, columnspan=1) + ttk.Label(t_ui, text='节气 ').grid(row=0, column=3) + ChoicesCombobox(t_ui, choices=delta_choices, val_variable=self._vm.vars['t_delta'], width=ccb_w).grid( + row=0, column=4, columnspan=1) + ChoicesCombobox(t_ui, choices=index_choices, val_variable=self._vm.vars['t_index'], empty_value=0, + width=ccb_w).grid(row=0, column=5, columnspan=1) + ttk.Combobox(t_ui, values=gz_day_choices, textvariable=self._vm.vars['t_day_gz'], state='readonly', width=ccb_w).grid( - row=t_row, column=6, columnspan=1) - ttk.Label(frame, text='日').grid(row=t_row, column=7) + row=0, column=6, columnspan=1) + ttk.Label(t_ui, text='日').grid(row=0, column=7) - # Toolbar 8 cols - ttk.Button(frame, text='创建节日', command=self._create).grid(row=btn_row, column=0, columnspan=8, - sticky='we') + ttk.Button(frame, text='创建节日', command=self._create).pack(side='top', fill='x') self._msg_label = MessageLabel(frame, text='') - self._msg_label.grid(row=msg_row, column=0, columnspan=10) - - for er in empty_rows: - ttk.Label(frame).grid(row=er, column=0, columnspan=7) + self._msg_label.pack(side='top') - # init form values self._vm.init() self._festival_detail = tk.StringVar() @@ -262,26 +260,26 @@ def _create(self, event=None): try: festival = self._vm.validate() self._festival_table.add_festival(festival) - self._msg_label.splash(f'{festival.description} {festival.encode()}', foreground='green') + self._msg_label.show_success_splash(f'{festival.description} {festival.encode()}') except ValidateError as e: - self._msg_label.splash(str(e), foreground='red') + self._msg_label.show_error_splash(str(e)) def _delete(self, event=None): self._festival_table.delete_selected_festivals() def _clear_data(self, event=None): self._festival_table.clear_data() - self._msg_label.splash('清空成功!', foreground='green') + self._msg_label.show_success_splash('清空成功!') def _export(self, event=None): if len(self._festival_table.tree_view.get_children()) == 0: - self._msg_label.splash('表格无数据!', foreground='red') + self._msg_label.show_warning_splash('表格无数据!') return filename = filedialog.asksaveasfilename(parent=self, title='保存到', defaultextension='.csv', filetypes=(('csv', 'csv'),)) if filename: self._festival_table.festival_library.to_csv(filename) - self._msg_label.splash('导出成功', foreground='green') + self._msg_label.show_success_splash('导出成功') def _on_source_selected(self, val: str): if val == 'custom': @@ -299,7 +297,7 @@ def _open_and_add(self, event=None): def _load_new_festival_library(self, f_library: FestivalLibrary): self._festival_table.add_festivals_from_library(f_library) - self._msg_label.splash(f'加载成功,共{self._festival_table.row_count}条', foreground='green') + self._msg_label.show_success_splash(f'加载成功,共{self._festival_table.row_count}条') def start_festival_creator(): diff --git a/borax/ui/widgets.py b/borax/ui/widgets.py index 7fddc82..d0b8fae 100644 --- a/borax/ui/widgets.py +++ b/borax/ui/widgets.py @@ -66,5 +66,14 @@ def show_text(self, text: str, text_color: str = 'black', splash_ms: int = 0): if splash_ms: self.after(splash_ms, self._clear) + def show_error_splash(self, text: str, splash_ms: int = 1000): + self.show_text(text, text_color='error', splash_ms=splash_ms) + + def show_warning_splash(self, text: str, splash_ms: int = 1000): + self.show_text(text, text_color='warning', splash_ms=splash_ms) + + def show_success_splash(self, text: str, splash_ms: int = 1000): + self.show_text(text, text_color='success', splash_ms=splash_ms) + def _clear(self): self.config({'text': ''}) diff --git a/docs/capp_changelog.md b/docs/capp_changelog.md new file mode 100644 index 0000000..63d1a5f --- /dev/null +++ b/docs/capp_changelog.md @@ -0,0 +1,11 @@ +# Borax.Capp 变更日志 + +Borax.Capp 是一个自带基于 tkinter 开发的日历应用程序。其版本号同 Borax 库。 + +## v4.1.1 + +- 优化节日创建界面布局 + +## v4.1.0 + +- 发布 Borax.Capp \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md index 9c4aa6d..d6331ae 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,12 @@ # 更新日志 +## v4.1.1 (20240630) + +- 新增创建农历年或农历月最后一天的方法 `LunarDate.last_day` +- `SolarFestival` 和`LunarFestival` 初始化函数 `freq` 参数支持字符串设置( [ #56](https://github.com/kinegratii/borax/issues/56) ) +- `Period.solar_year` 和 `Period.lunar_year` 新增 `end_year` 参数,支持跨年份计算 +- 废弃模块:`borax.choices` + ## v4.1.0 (20240131) > Borax最低python版本要求为python3.9 diff --git a/docs/guides/choices.md b/docs/guides/choices.md index 770c1a6..cf868f6 100644 --- a/docs/guides/choices.md +++ b/docs/guides/choices.md @@ -2,7 +2,11 @@ > 模块: `borax.choices` -> Update in v3.4.0 +> Changed in v3.4.0 :适配 Django choices + +## 重要信息 + +从 Borax 4.1.0 开始,本模块被标记为 废弃 状态,推荐使用标准的 Django Choices 。关于如何迁移参考下列文档。 ## 开发背景 @@ -85,14 +89,14 @@ class YearInSchoolChoices(choices.ConstChoices): 可以直接使用 `YearInShoolChoices.FRESHMAN` 访问该选项具体的值。 - ```bash - >>> YearInShoolChoices.FRESHMAN +```bash +>>> YearInShoolChoices.FRESHMAN 'FR' >>> YearInShoolChoices.is_valid('SR') True >>> YearInShoolChoices.is_valid('Et') False - ``` +``` ## 选项(Item) ### 显式Item定义 @@ -209,7 +213,7 @@ class DirectionChoices(VerticalChoices): -## 关于Django.Choices +## 与Django.Choices ### 概述 @@ -234,12 +238,12 @@ from django.db import models from borax import choices -class MyChoices(models.TextChoices): +class MyChoices(models.TextChoices): # Django choices style GREEN = 'g', 'green' RED = 'r', 'red' YELLOW = 'y', 'yellow' -class MyChoices(choices.Choices): +class MyChoices(choices.Choices): # Borax choices style GREEN = 'g', 'green' RED = 'r', 'red' YELLOW = 'y', 'yellow' @@ -248,19 +252,23 @@ class MyChoices(choices.Choices): 表 Borax.Choices *VS* Django.Choices -| | Borax.Choices | Django.Choices | 备注 | -| --------------------------- | ------------- | ------------------ | ---- | -| MyChoices.choices | `(...)` | `(...)` | | -| MyChoices.GREEN | `'g'` | `` | | -| MyChoices['GREEN'] | - | `` | | -| MyChoices.is_valid('g') | True | - | | -| MyChoices.GREEN.name | - | `'g'` | | -| MyChoices.GREEN.label | - | `'green'` | | -| MyChoices.GREEN.value | - | - | | -| MyChoices.GREEN.display | - | - | | -| MyChoices.get_value_display | `