EDITADO:
Como posso definir o padrão de um campo Django para uma função que é avaliada cada vez que um novo objeto de modelo é criado?
Eu quero fazer algo como o seguinte, exceto que neste código, o código é avaliado uma vez e define o padrão para a mesma data para cada objeto de modelo criado, em vez de avaliar o código cada vez que um objeto de modelo é criado:
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))
ORIGINAL:
Quero criar um valor padrão para um parâmetro de função de forma que seja dinâmico e seja chamado e definido toda vez que a função for chamada. Como eu posso fazer isso? por exemplo,
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
Especificamente, quero fazer isso em Django, por exemplo,
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))
django
django-models
parameters
lambda
default
Rob Bednark
fonte
fonte
Respostas:
A pergunta está equivocada. Ao criar um campo de modelo no Django, você não está definindo uma função, então os valores padrão da função são irrelevantes:
Esta última linha não está definindo uma função; é invocar uma função para criar um campo na classe.
PRE Django 1.7
Django permite que você passe um callable como o padrão , e ele irá invocá-lo todas as vezes, assim como você deseja:
Django 1.7+
Observe que desde o Django 1.7, o uso de lambda como valor padrão não é recomendado (cf comentário @stvnw). A maneira correta de fazer isso é declarar uma função antes do campo e usá-la como um callable em default_value chamado arg:
Mais informações na resposta @simanas abaixo
fonte
get_default_my_date
?Fazer isso
default=datetime.now()+timedelta(days=1)
é absolutamente errado!Ele é avaliado quando você inicia sua instância do django. Se você estiver usando o apache, provavelmente funcionará, porque em algumas configurações o apache revoga seu aplicativo django em todas as solicitações, mas ainda assim você pode se encontrar algum dia olhando seu código e tentando descobrir por que isso não foi calculado como você esperava .
A maneira certa de fazer isso é passar um objeto que pode ser chamado para o argumento padrão. Pode ser uma função datetime.today ou sua função personalizada. Então, ele é avaliado toda vez que você solicita um novo valor padrão.
fonte
get_deadline(my_parameter)
?deadline
campo novamente enquanto exclui aget_deadline
função? Removi um campo com uma função para um valor padrão, mas agora o Django falha na inicialização após remover a função. Eu poderia editar manualmente a migração, o que estaria correto neste caso, mas e se você simplesmente alterasse a função padrão e quisesse remover a função antiga?Há uma distinção importante entre os dois construtores DateTimeField a seguir:
Se você usar
auto_now_add=True
no construtor, a data e hora referenciada por my_date é "imutável" (definida apenas uma vez quando a linha é inserida na tabela).Com
auto_now=True
, entretanto, o valor datetime será atualizado sempre que o objeto for salvo.Isso foi definitivamente um problema para mim em um ponto. Para referência, os documentos estão aqui:
https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield
fonte
Às vezes, você pode precisar acessar os dados do modelo após criar um novo modelo de usuário.
Aqui está como eu gero um token para cada novo perfil de usuário usando os primeiros 4 caracteres de seu nome de usuário:
fonte
Você não pode fazer isso diretamente; o valor padrão é avaliado quando a definição da função é avaliada. Mas existem duas maneiras de contornar isso.
Primeiro, você pode criar (e depois chamar) uma nova função a cada vez.
Ou, mais simplesmente, use um valor especial para marcar o padrão. Por exemplo:
Se
None
for um valor de parâmetro perfeitamente razoável e não houver outro valor razoável que você possa usar em seu lugar, você pode apenas criar um novo valor que está definitivamente fora do domínio de sua função:Em alguns casos raros, você está escrevendo um meta-código que realmente precisa ser capaz de pegar absolutamente qualquer coisa, mesmo, digamos
mydate.func_defaults[0]
,. Nesse caso, você deve fazer algo assim:fonte
myfunc
função é feita para pegar (e imprimir) umdatetime
; você o alterou, então não pode ser usado dessa forma.Passe a função como um parâmetro em vez de passar o resultado da chamada da função.
Ou seja, em vez disso:
Experimente isto:
fonte
print datetime.now()
incondicionalmente.datetime.now
função. Mas qualquer usuário que passar um valor não padrão estará passando uma data e hora, não uma função.foo = datetime.now(); myfunc(foo)
vai aumentarTypeError: 'datetime.datetime' object is not callable
. Se eu realmente quisesse usar sua função, teria que fazer algo comomyfunc(lambda: foo)
, que não é uma interface razoável.