【问题标题】:Only showing year in django admin, a YearField instead of DateField?仅在 django admin 中显示年份,YearField 而不是 DateField?
【发布时间】:2010-12-03 19:12:05
【问题描述】:

我有一个模型需要存储出生年份。我正在使用 django 管理员。使用它的人每天都会填写大量的人,并且 DateField() 显示太多(对日/月不感兴趣)。

这是一个展示它现在的样机模型:

class Person(models.Model):
  name = models.CharField(max_length=256)
  born = models.IntegerField(default=lambda: date.today().year - 17)

如您所见,大多数人都是 17 岁,所以我将他们的出生年份作为默认值。

我可以做得更好吗?如何从 DateField 中创建 YearField?如果制作一个 YearField,我什至可以制作一些“简单的标签”,比如那个日期的“现在”。 (当然,专门的 BornYearField 将有 1989、1990、1991 和其他常见年份的简单按钮)

【问题讨论】:

    标签: django datetime django-admin datefield


    【解决方案1】:

    我发现 this solution 我认为它非常优雅地解决了整个问题(不是我的代码):

    import datetime
    YEAR_CHOICES = []
    for r in range(1980, (datetime.datetime.now().year+1)):
        YEAR_CHOICES.append((r,r))
    
    year = models.IntegerField(_('year'), choices=YEAR_CHOICES, default=datetime.datetime.now().year)
    

    编辑范围开始以扩展列表:-)

    【讨论】:

    • 您可以在一行中完成所有操作:YEAR_CHOICES = [(r,r) for r in range(1984, datetime.date.today().year+1)]
    • 默认应该看起来像default=lambda: datetime.datetime.now().year 否则它只会在服务重启时更新默认
    • 另外,如果你想让迁移工作,那么你不能使用 lambda,所以你需要定义一个简单的函数 def current_year(): ... 并使用它(不带括号)而不是 default=current_year
    • 您应该删除max_length=4IntergerField 将被忽略。
    • 我创建了类似:def YEAR_CHOICES(): year_choices = [] for r in range(1980, (datetime.datetime.now().year + 1)): year_choices.append((r, r)) return year_choices 的函数并在类中使用:class Education(models.Model): year_of_passing = models.IntegerField(_('year_of_passing'), choices=YEAR_CHOICES, default=datetime.datetime.now().year) 但它的抛出错误:resume.Education.year_of_passing: (fields.E004) 'choices' 必须是可迭代的(例如,列表或元组)。我做错了什么?
    【解决方案2】:

    另外,这与您的情况无关,但注意不要使用 datetime.date.today() 或 datetime.datetime.now() 作为默认值。这会在服务器启动时执行一次。

    你最好把可调用对象传入:

    date = models.DateField(default=datetime.date.today)
    

    注意,您可以使用 lambda 使其相对:

    date = models.DateField(default=lambda : datetime.date.today() - datetime.timedelta(days=6210))
    

    当然,这是幼稚的,假设过去 17 年有 5 个闰年。

    【讨论】:

    • 是的,我知道这个问题。但是,我想既然这是一个年字段,只是为了帮助人们整天添加新成员,它只需要每年更新一次。它只需要“几乎达到”平均年龄。不过谢谢,lambda 解决方案当然更好。
    • 只是我,还是这个被赞成的答案与问题无关?
    【解决方案3】:

    你也可以这样做:

    YEARS = (
        ("1990", "1990"),
        ("1991", "1991"),
        ("1992", "1992"),
        # P.e. generate a list from 1960 to date.today().year
        # The reason why they choice key and text value are the
        # same is that if you generate from 1960 to 2060 it will collide.
        #
        # E.g
        # from datetime import datetime
        # def tuplify(x): return (x,x)   # str(x) if needed
        # current_year = datetime.now().year
        # YEARS = map(tuplify, range(1930, current_year + 1))  # range(1,4) gives [1,2,3]
    )
    
    class Whatever(models.Model):
        # Show a list with years
        birthdate = models.IntegerField(max_length=2, choices=YEARS)
    

    希望对你有帮助。

    【讨论】:

    • Django 忽略 max_lengthIntegerField,并会在 Django 1.8+ 中警告你。请参阅this 了解更多信息。
    • 你的 YEARS 元组的第一个元素应该是一个整数,因为生日的类型是 IntegerField。您可以在此处使用列表推导来构建选择并拥有一个相当简单的语句。
    【解决方案4】:

    对于不涉及模型选择的解决方案:

    from django.core.validators import MinValueValidator, MaxValueValidator
    
    class Person(models.Model):
        year = models.PositiveIntegerField(
                validators=[
                    MinValueValidator(1900), 
                    MaxValueValidator(datetime.now().year)],
                help_text="Use the following format: <YYYY>")
    

    这还将在输入字段中创建一个占位符,其值为help_text

    【讨论】:

      猜你喜欢
      • 2011-01-11
      • 2018-12-30
      • 2011-03-05
      • 2022-07-25
      • 2011-06-11
      • 1970-01-01
      • 2019-02-09
      • 2021-12-31
      • 1970-01-01
      相关资源
      最近更新 更多