tutorial proyecto modelos formularios estructura ejemplos avanzados django django-models parameters lambda default

proyecto - Cómo establecer el valor predeterminado de un campo de modelo Django en una llamada de función/invocable(por ejemplo, una fecha relativa al momento de creación del objeto modelo)



modelos en django (6)

EDITADO:

¿Cómo puedo establecer el campo predeterminado de Django en una función que se evalúa cada vez que se crea un nuevo objeto modelo?

Quiero hacer algo como lo siguiente, excepto que en este código, el código se evalúa una vez y establece el valor predeterminado en la misma fecha para cada objeto de modelo creado, en lugar de evaluar el código cada vez que se crea un objeto modelo:

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:

Quiero crear un valor predeterminado para un parámetro de función tal que sea dinámico y se llame y configure cada vez que se llame a la función. ¿Cómo puedo hacer eso? p.ej,

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

Específicamente, quiero hacerlo en Django, por ejemplo,

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))


En ocasiones, es posible que necesite acceder a los datos del modelo después de crear un nuevo modelo de usuario.

Así es como genero un token para cada nuevo perfil de usuario usando los primeros 4 caracteres de su nombre de usuario:

from django.dispatch import receiver class Profile(models.Model): auth_token = models.CharField(max_length=13, default=None, null=True, blank=True) @receiver(post_save, sender=User) # this is called after a User model is saved. def create_user_profile(sender, instance, created, **kwargs): if created: # only run the following if the profile is new new_profile = Profile.objects.create(user=instance) new_profile.create_auth_token() new_profile.save() def create_auth_token(self): import random, string auth = self.user.username[:4] # get first 4 characters in user name self.auth_token = auth + ''''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(random.randint(3, 5)))


Hacer esto default=datetime.now()+timedelta(days=1) es absolutamente incorrecto!

Se evalúa cuando comienza su instancia de django. Si estás bajo apache, probablemente funcione, porque en algunas configuraciones apache revoca tu aplicación django en cada solicitud, pero aún puedes encontrarte algún día revisando tu código e intentando averiguar por qué esto no se calcula como esperabas .

La forma correcta de hacerlo es pasar un objeto invocable al argumento predeterminado. Puede ser una función datetime.today o su función personalizada. Luego se evalúa cada vez que solicita un nuevo valor predeterminado.

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)


Hay una distinción importante entre los siguientes dos constructores DateTimeField:

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

Si usa auto_now_add=True en el constructor, la fecha a la que hace referencia my_date es "inmutable" (solo se establece una vez cuando la fila se inserta en la tabla).

Con auto_now=True , sin embargo, el valor de fecha y hora se actualizará cada vez que se guarde el objeto.

Esto fue definitivamente un problema para mí en un punto. Como referencia, los documentos están aquí:

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


La pregunta es equivocada. Al crear un campo de modelo en Django, no está definiendo una función, por lo que los valores predeterminados de la función son irrelevantes:

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))

Esta última línea no define una función; está invocando una función para crear un campo en la clase.

PRE Django 1.7

Django le permite pasar un invocable como predeterminado y lo invocará cada vez, tal como lo desea:

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))

Django 1.7+

Tenga en cuenta que desde Django 1.7, no se recomienda el uso de lambda como valor predeterminado (cf @stvnw comment). La forma correcta de hacerlo es declarar una función antes del campo y usarla como un valor invocable en default_value llamado arg:

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)

Más información en la respuesta de @simanas a continuación


No puedes hacer eso directamente; el valor predeterminado se evalúa cuando se evalúa la definición de la función. Pero hay dos formas de evitarlo.

Primero, puede crear (y luego llamar) una nueva función cada vez.

O, más simplemente, simplemente use un valor especial para marcar el valor predeterminado. Por ejemplo:

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

Si None es un valor de parámetro perfectamente razonable, y no hay otro valor razonable que pueda usar en su lugar, puede crear un valor nuevo que esté definitivamente fuera del dominio de su función:

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

En algunos casos excepcionales, está escribiendo meta-código que realmente necesita poder tomar absolutamente cualquier cosa, incluso, por ejemplo, mydate.func_defaults[0] . En ese caso, debes hacer algo como esto:

def mydate(*args, **kw): if ''date'' in kw: date = kw[''date''] elif len(args): date = args[0] else: date = datetime.now() print date


Pase la función como un parámetro en lugar de pasar el resultado de la llamada a la función.

Es decir, en lugar de esto:

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

Prueba esto:

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