vadim_v
vadim_v

Reputation: 113

Django Datetime Choice field issue

So, I am quite new to Django, and I am trying to put the following idea into practice: In my object creation form I want users to fill a date field in order to put a timestamp of sorts on the object. The catch is that I want to make only two days available for choosing - today and tomorrow. I do not want to use DateTime field and make users type in the dates by hand as it looks quite ugly and not really convenient to use. I decided to try and implement a choice field. It gets rendered well, but so far I have not figured out how to make my form data pass as valid. I have poked around with pdb, as a result read about cleaning/validating methods but I still have no idea how to get this to work. What I already tried: adding functions that return today and tomorrow as date objects and as strings (here is the latter) the error text is: select a valid choice, is not one of the available choices I perceive that it fails during clean() method somehow. Or, if it is not a reasonable idea (which it probably is not), what might be an alternative?

models.py:

def get_today():
    return datetime.date.strftime( datetime.datetime.now().date(), format="%Y-%m-%d")

def get_tomorrow():
    return datetime.date.strftime(((datetime.datetime.now() + datetime.timedelta(days=1)).date()), format="%Y-%m-%d") 

class User(AbstractUser):

    slug = models.SlugField(max_length=100, unique=True)

    def save(self, *args, **kwargs):
        self.slug = slugify(self.username)
        super(User, self).save(*args, **kwargs)


class Task(models.Model):
    TODAY = get_today
    TOMORROW = get_tomorrow
    DATE_SELECTION = (
            (TODAY, "Today"),
            (TOMORROW, "Tomorrow"),
        )
    task_title = models.CharField(verbose_name="Название задачи: ", max_length=150)
    task_description = models.TextField(verbose_name="Описание: ", max_length=1000)
    task_user = models.ForeignKey('User', on_delete=models.CASCADE)
    task_date = models.DateField(choices=DATE_SELECTION)

    def __str__(self):
        return self.task_title

the class-based view from views.py that I use to process the form:

class CreateTask(CreateView):
    model = Task
    form_class = TaskForm
    success_url = '/{user}'

    def get(self, request, *args, **kwargs):
        form = TaskForm()
        return render(request, 'create_task.html', {'form': form})

    def post(self, request, *args, **kwargs):
        form = TaskForm(request.POST)
        if form.is_valid():
            task = form.save(commit=False)
            task = Task(**form.cleaned_data)
            task.task_user = request.user
            task.save()
            messages.add_message(request, messages.INFO, "Task %s was successfully created!" % task.task_title)
            return redirect('tasks:user_home', user=request.user)
        else:
            return render(request, 'create_task.html', {'form': form, 'errors':form.errors}) 

forms.py

class TaskForm(forms.ModelForm):    
    task_date=forms.DateField(input_formats="%Y-%m-%d")
    class Meta:
        model = Task
        fields = ['task_title', 'task_description']

UPDATE: after lots of experiments and research I created the following solution:

models.py

class Task(models.Model):
    task_title = models.CharField(verbose_name="Название задачи: ", max_length=150)
    task_description = models.TextField(verbose_name="Описание: ", max_length=1000)
    task_user = models.ForeignKey('User', on_delete=models.CASCADE)
    task_date = models.DateField()

    def __str__(self):
        return self.task_title

(^^^note the lack of selection field) and forms.py:

def get_today():
    return datetime.datetime.now().date()

def get_tomorrow():
    return (datetime.datetime.now() + datetime.timedelta(days=1)).date() 

TODAY = get_today
TOMORROW = get_tomorrow
DATE_SELECTION = (
        (TODAY, "Today"),
        (TOMORROW, "Tomorrow"),
    )

class TaskForm(forms.ModelForm):    
    task_date = forms.DateField(input_formats=["%Y-%m-%d"], widget=forms.Select(choices=DATE_SELECTION))
    class Meta:
        model = Task
        fields = ['task_title', 'task_description']

(^^^note the select widget, input_formats, which must always be a list)

Upvotes: 1

Views: 3069

Answers (1)

vadim_v
vadim_v

Reputation: 113

UPDATE: after lots of experiments and research I created the following solution:

models.py

class Task(models.Model):
    task_title = models.CharField(verbose_name="Название задачи: ", max_length=150)
    task_description = models.TextField(verbose_name="Описание: ", max_length=1000)
    task_user = models.ForeignKey('User', on_delete=models.CASCADE)
    task_date = models.DateField()

    def __str__(self):
        return self.task_title

(^^^note the lack of selection field) and forms.py:

def get_today():
    return datetime.datetime.now().date()

def get_tomorrow():
    return (datetime.datetime.now() + datetime.timedelta(days=1)).date() 

TODAY = get_today
TOMORROW = get_tomorrow
DATE_SELECTION = (
        (TODAY, "Today"),
        (TOMORROW, "Tomorrow"),
    )

class TaskForm(forms.ModelForm):    
    task_date = forms.DateField(input_formats=["%Y-%m-%d"], widget=forms.Select(choices=DATE_SELECTION))
    class Meta:
        model = Task
        fields = ['task_title', 'task_description']

(^^^note the select widget, input_formats, which must always be a list)

Upvotes: 4

Related Questions