Date de création automatique des objets de formulaire de modèle Django?

153

Quelle est la meilleure façon de définir automatiquement une date de création pour un objet, ainsi qu'un champ qui enregistrera la dernière mise à jour de l'objet?

models.py:

created_at = models.DateTimeField(False, True, editable=False)
updated_at = models.DateTimeField(True, True, editable=False)

views.py:

if request.method == 'POST':
    form = MyForm(request.POST)
    if form.is_valid():
        obj = form.save(commit=False)
        obj.user = request.user
        obj.save()
        return HttpResponseRedirect('obj_list')

J'obtiens l'erreur:

objects_object.created_at may not be NULL

Dois-je définir manuellement cette valeur moi-même? Je pensais que c'était le but des paramètres passés à DateTimeField(ou sont-ils juste des valeurs par défaut, et depuis que j'ai défini, editable=Falseils ne sont pas affichés sur le formulaire, donc ne sont pas soumis dans la demande, et donc mettre dans le formulaire?).

Quelle est la meilleure façon de procéder? Une __init__méthode?

Roger
la source

Réponses:

313

Vous pouvez utiliser les auto_nowet les auto_now_addoptions pour updated_atet created_atrespectivement.

class MyModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
Manoj Govindan
la source
31
auto_nowet auto_now_addsont considérés comme mauvais, alors essayez de les éviter. Cette réponse explique pourquoi et fournit une meilleure approche, supplantant la save()méthode.
gregoltsov
3
il produit cette erreur:You are trying to add a non-nullable field 'created_at' to gameuser without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows) 2) Quit, and let me add a default in models.py Select an option: 1 Please enter the default value now, as valid Python The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now() >>> timezone.now()
Kaleem Ullah
1
supprimez les lignes de la base de données, ou cochez l'option 1 et ajoutez timezone.now ()
mullerivan
1
Je pense que le commentaire de @ gregoltsov est dépassé à ce stade. Utilisation auto_now_addou auto_nowfonctionne très bien. Il définit le champ avant d'enregistrer le modèle ( github.com/django/django/blob/stable/3.0.x/django/db/models/… ).
yndolok le
26

Eh bien, la réponse ci-dessus est correcte, auto_now_add et auto_now le feraient, mais il serait préférable de créer une classe abstraite et de l'utiliser dans n'importe quel modèle où vous avez besoin created_atet des updated_atchamps.

class TimeStampMixin(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

Maintenant, partout où vous voulez l'utiliser, vous pouvez faire un héritage simple et vous pouvez utiliser l'horodatage dans n'importe quel modèle que vous aimez.

class Posts(TimeStampMixin):
    name = models.CharField(max_length=50)
    ...
    ...

De cette façon, vous pouvez tirer parti de la réutilisabilité orientée objet, dans Django DRY (ne vous répétez pas)

Chitrank Dixit
la source