Zedh
Zedh

Reputation: 155

Django - Set current date as initial/default in a DateField form with SelectDateWidget

I have a model:

class Planning (models.Model):

#other fields#

month = models.DateField(default=date.today)

class Meta:
    verbose_name_plural = 'Planning'

And I have this model form:

class PlanningForm(forms.ModelForm):
    
#other fields#

month = forms.DateField(
    label='Mês/Ano',
    required=True,
    widget=forms.SelectDateWidget(
        attrs={'type': 'date',
               'value': date.today},}),
    error_messages={'required': '', },
)
 
    class Meta:
        model = Planning
        fields = '__all__'

The view:

def new_planning(request):
form = PlanningForm(request.POST)
if form.is_valid():
    form.save()
    if 'another' in request.POST:
        messages.success(request, ('Lançamento salvo com sucesso!'))
        return redirect('app:new_planning')
    else:
        return redirect('app:list_planning')
return render(request, 'app/pages/planning/new_planning.html', context={
    'form': form,
})

I'm using SelectDateWidget to show only month/year (I hid the day selector using CSS), like this:

enter image description here

The form is working as intended, but the issue is that I can't set the field to show the current date. When the form is rendered, it always shows the first date of the year.

In the above code, I tried to show the date using the value attribute from HTML. This works perfectly when I use widget=forms.DateInput but I imagine that the widget is changing the input completely so it doesn't work.

I also tried to add an initial value the same way I did for the model using the line initial=date.today, but for what i can get, this only works for unbound forms and since my view runs a if form.is_valid():, that is not the case.

And I did try to set a range for the months, along the lines of this question, but with no luck.

Is there a way to set the current date with this specific widget?

Edit:

I could be completely wrong, but I'm assuming that the date input is converted to an actual date AFTER save. In this widget you can set a list/tuple/dict with the values you want to show. So if it is converting the values to dates after save, it make sense that it doesn't recognize the current date. To test this I added a list and dict with the months and years choice:

class PlanningForm(forms.ModelForm):

MONTHS = {1: ('this'), 2: ('is'), 3: ('text'), }
YEARS = ['and_so_is_this']

month = forms.DateField(
    label='Mês/Ano',
    required=True,
    widget=forms.SelectDateWidget(
        months=MONTHS,
        years=YEARS,
        attrs={'type': 'date', }),
    error_messages={'required': '', },
)

And the result:

enter image description here

Upvotes: 2

Views: 1818

Answers (1)

Clepsyd
Clepsyd

Reputation: 551

You should be able to do this by overriding the __init__ method:

from datetime import datetime

class PlanningForm(forms.ModelForm):
    # ...
    month = forms.DateField(
        label="Mês/Ano",
        required=True,
        widget=forms.SelectDateWidget(attrs={"type": "date"}),
        error_messages={
            "required": "",
        },
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['month'].initial = datetime.now()  # or timezone aware equivalent
    
    # ...

I think there's also an issue with the indentation and parentheses of your month field declaration

EDIT: It seems that the initial value must be a datetime object.

EDIT 2: The view and template I've used to test this

View:

class PlanningView(FormView):
    form_class = PlanningForm
    template_name = "planning/form.html"

Template:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  {{ form }}
</body>
</html>

Upvotes: 3

Related Questions