Search code examples
djangodjango-modelsdjango-viewsdjango-forms

Django: Update form without updating date/time when Date/TimeField is auto_now=True


I have build a record keeping app. I want the user to be able to edit an event but without updating the Date/TimeField when those are set to auto_now=True.

models.py

class Game(models.Model):
    # ForeignKeys
    user = models.ForeignKey(User,
                             max_length=10,
                             on_delete=models.CASCADE,
                             null=True)
    deck = models.ForeignKey(Deck, on_delete=models.CASCADE, null=True)
    wincon = models.ForeignKey(Wincon, on_delete=models.CASCADE, null=True, blank=True)
    tournament = models.BooleanField(default=False)

    num_players = models.IntegerField(choices=NUM_PLAYERS_CHOICE, default=4)
    start_pos = models.CharField(max_length=20, choices=START_POS_CHOICE, default=1)
    mull = models.CharField(max_length=20, choices=MULL_CHOICE, default='1st 7')
    outcome = models.CharField(max_length=10, choices=OUTCOME_CHOICE, default='Win')
    medium = models.CharField(max_length=10, choices=MEDIUM_CHOICE, default='Paper')
    date = models.DateField(auto_now=True)
    time = models.TimeField(auto_now=True)

forms.py

class GameForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(GameForm, self).__init__(*args, **kwargs)

        # Set deck list shown to only decks from user
        user_decks = Deck.objects.filter(user=user)
        user_decks_list = []
        for deck in user_decks:
            if deck.is_cedh:
                deck.deck += ':  cEDH'
            user_decks_list.append((deck.id, deck.deck))
        self.fields['deck'].choices = user_decks_list

        # Set wincon list shown to only wincon from user
        user_wincon = Wincon.objects.filter(user=user)
        user_wincon_list = []
        for wincon in user_wincon:
            user_wincon_list.append((wincon.id, wincon.wincon))
        self.fields['wincon'].choices = user_wincon_list

    class Meta:
        model = Game
        exclude = {'date', 'time', 'user'}
        labels = {
            'deck': 'What deck',
            'num_players': '# of Players',
            'start_pos': 'Starting position',
            'mull': 'Starting hand',
            'outcome': 'Outcome',
            'wincon': 'Your Wincon',
            'medium': 'Paper or Online',
            'tournament': 'Tournament',
        }

class UpdateGameForm(forms.ModelForm):
    class Meta:
        model = Game
        exclude = {'date', 'time', 'user'}
        fields = {
            'deck': 'What deck',
            'num_players': '# of Players',
            'mull': 'Starting hand',
            'outcome': 'Outcome',
            'wincon': 'Wincon',
            'medium': 'Paper or Online',
            'tournament': 'Tournament',
        }

views.py

@login_required(login_url='my-login')
def game_tracker(request):
    user = User.objects.get(username=request.user)
    user_decks = Deck.objects.filter(user=request.user)
    user_wincon = Wincon.objects.filter(user=request.user)

    if request.method == "POST":
        form = GameForm(request.user, request.POST)
        if form.is_valid():
            obj = form.save(commit=False)
            obj.user = user
            obj.save()
            return HttpResponseRedirect('/view-games')
    else:
        form = GameForm(request.user)

    context = {'form': form, 'user_decks': user_decks, 'user_wincon': user_wincon, 'user': user, }
    return render(request, 'gametracker_app/gametracker.html', context=context)


@login_required(login_url='my-login')
def update_game(request, game_id):
    game = Game.objects.get(pk=game_id)
    form = UpdateGameForm(request.POST or None, instance=game)
    if form.is_valid():
        form.save()
        return redirect('/view-games')

    context = {'game': game, 'form': form}
    return render(request, 'gametracker_app/update-game.html', context=context)

In forms.py I was trying to 'set' the date and time fields to what they previously were. This is what I had done with setting the 'deck' choices to the 'user_deck_list' but I don't know how to get the value of date/time to set the value because I am using auto_now=True in my models.

class UpdateGameForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(UpdateGameForm, self).__init__(*args, **kwargs)
        self.fields['date'] = 'date'
        self.fields['time'] = 'time'

Solution

  • Use auto_now_add = True because:

    auto_now option is used to set the value of the field to the current date and time every time the model instance is saved, regardless of whether it is being created or updated.

    auto_now_add option, on the other hand, is used to set the value of the field to the current date and time only when the model instance is created.