Reputation: 113
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
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