123

編集:

Django フィールドのデフォルトを、新しいモデル オブジェクトが作成されるたびに評価される関数に設定するにはどうすればよいですか?

次のようなことをしたいと思います。ただし、このコードでは、モデル オブジェクトが作成されるたびにコードを評価するのではなく、コードが 1 回評価され、作成されたモデル オブジェクトごとにデフォルトが同じ日付に設定される点が異なります。

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))



オリジナル:

関数パラメーターのデフォルト値を作成して、動的であり、関数が呼び出されるたびに呼び出されて設定されるようにしたいと考えています。どうやってやるの?例えば、

from datetime import datetime
def mydate(date=datetime.now()):
  print date

mydate() 
mydate() # prints the same thing as the previous call; but I want it to be a newer value

具体的には、Djangoでやりたいです。

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))
4

6 に答える 6

161

質問は見当違いです。Django でモデル フィールドを作成する場合、関数を定義していないため、関数のデフォルト値は関係ありません。

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))

この最後の行は関数を定義していません。クラスにフィールドを作成する関数を呼び出しています。

この場合datetime.now() + timedelta(days=1)、一度評価され、デフォルト値として保存されます。

以前のジャンゴ 1.7

Django [callable をデフォルトとして渡すことができます][1]、必要に応じて毎回呼び出します。

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=lambda: datetime.now() + timedelta(days=1))

ジャンゴ 1.7+

Django 1.7 以降、ラムダをデフォルト値として使用することは推奨されないことに注意してください (@stvnw コメントを参照)。これを行う適切な方法は、フィールドの前に関数を宣言し、それを arg という名前の default_value で callable として使用することです。

from datetime import datetime, timedelta

# default to 1 day from now
def get_default_my_date():
  return datetime.now() + timedelta(days=1)

class MyModel(models.Model):
  my_date = models.DateTimeField(default=get_default_my_date)

[1] 以下の @simanas の回答の詳細: https://docs.djangoproject.com/en/dev/ref/models/fields/#default

于 2012-09-29T17:46:34.823 に答える
70

これを行うのdefault=datetime.now()+timedelta(days=1)は絶対に間違っています!

django のインスタンスを起動すると評価されます。一部の構成では、apache はすべてのリクエストで django アプリケーションを取り消すため、apache を使用している場合はおそらく機能しますが、それでもいつかコードを調べて、これが期待どおりに計算されない理由を理解しようとすることができます。 .

これを行う正しい方法は、呼び出し可能なオブジェクトをデフォルト引数に渡すことです。datetime.today 関数またはカスタム関数にすることができます。その後、新しいデフォルト値をリクエストするたびに評価されます。

def get_deadline():
    return datetime.today() + timedelta(days=20)

class Bill(models.Model):
    name = models.CharField(max_length=50)
    customer = models.ForeignKey(User, related_name='bills')
    date = models.DateField(default=datetime.today)
    deadline = models.DateField(default=get_deadline)
于 2013-03-08T08:19:15.310 に答える
8

次の2つのDateTimeFieldコンストラクターには重要な違いがあります。

my_date = models.DateTimeField(auto_now=True)
my_date = models.DateTimeField(auto_now_add=True)

コンストラクターで使用する場合auto_now_add=True、my_dateによって参照される日時は「不変」です(行がテーブルに挿入されるときに一度だけ設定されます)。

ただし、を使用auto_now=Trueすると、オブジェクトが保存されるたびに日時の値が更新されます。

これは、ある時点で間違いなく私にとっての落とし穴でした。参考までに、ドキュメントは次のとおりです。

https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield

于 2012-09-29T07:06:18.040 に答える
3

直接行うことはできません。関数定義が評価されるときにデフォルト値が評価されます。しかし、それを回避する方法は 2 つあります。

まず、毎回新しい関数を作成 (および呼び出し) できます。

または、もっと単純に、特別な値を使用してデフォルトをマークします。例えば:

from datetime import datetime
def mydate(date=None):
  if date is None:
    date = datetime.now()
  print date

が完全に妥当なパラメータ値であり、その代わりに使用できる妥当な値が他にない場合Noneは、関数のドメイン外に確実にある新しい値を作成できます。

from datetime import datetime
class _MyDateDummyDefault(object):
  pass
def mydate(date=_MyDateDummyDefault):
  if date is _MyDateDummyDefault:
    date = datetime.now()
  print date
del _MyDateDummyDefault

いくつかのまれなケースでは、あなたは本当に何でも取ることができる必要があるメタコードを書いていますmydate.func_defaults[0]. その場合、次のようにする必要があります。

def mydate(*args, **kw):
  if 'date' in kw:
    date = kw['date']
  elif len(args):
    date = args[0]
  else:
    date = datetime.now()
  print date
于 2012-09-29T03:23:19.340 に答える
1

関数呼び出しの結果を渡す代わりに、関数をパラメーターとして渡します。

つまり、これの代わりに:

def myfunc(date=datetime.now()):
    print date

これを試して:

def myfunc(date=datetime.now):
    print date()
于 2012-09-29T04:43:47.523 に答える