Form shows wrong date format while changing element in Django - python

I need the date format dd-mm-yyyy and I changed it everywhere. The date in the list of elements shows correctly. The database also has a requirement to enter the date in this format.
However, when I try to modify an existing element, the form shows a date in the format yyyy-mm-dd and I have to change the date to dd-mm-yyyy each time to make changes to the element, otherwise an error occurs. How can I make the date displayed in the format dd-mm-yyyy by default when editing an element?
forms.py
class CaseRequestForm(forms.ModelForm):
class Meta:
model = CaseRequest
fields = ('name', 'datebirth')
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'datebirth': forms.TextInput(attrs={'class': 'form-control'}),
}
Models.py
class CaseRequest(models.Model):
name = models.CharField('Put full name',max_length=255)
datebirth = models.DateField('Put date in dd.mm.yy format')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('caserequest')
#property
def case_exists(self):
return Case.objects.filter(name=self.name, datebirth=self.datebirth).exists()
Views.py
class UpdateCaseRequestView(UpdateView):
model = CaseRequest
form_class = CaseRequestForm
template_name = 'add_caserequest.html'
update_caserequest.py
<div>
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button class="btn btn-secondary">Send</button>
</form>
</div>
In settings.py I already added
DATE_INPUT_FORMATS = ["%d.%m.%Y"]
USE_L10N = False

The default widget for the DateField is DateInput not TextInput, that's for CharField.
You can override its format in the widget itself so:
from django.forms import DateInput
class CaseRequestForm(forms.ModelForm):
class Meta:
model = CaseRequest
fields = ('name', 'datebirth')
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'datebirth': DateInput(attrs={'class': 'form-control'}, format='%d-%m-%Y'),
}
Now, the date input field in the form will use the dd-mm-yyyy format in the front-end.
Also provide %d-%m-%y in the DATE_INPUT_FORMATS since both are valid date formats so:
DATE_INPUT_FORMATS = ["%d.%m.%Y", "%d-%m-%Y"]
USE_L10N = False

Related

Django DateTimeField not showing up properly in browser

I want my django DateTimeField to be inputted the same way I input the values from the admin page, where the dates are selected from a calender.
for reference this is how my models.py look like:
from django.db import models
# Create your models here.
class TheDate(models.Model):
"""A topic the user is learning about"""
theDate = models.DateTimeField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""returns a string representation of the model"""
return str(self.theDate)
forms.py
class NewDate(forms.ModelForm):
class Meta:
model = TheDate
fields = ['theDate']
labels = {'theDate': ''}
the html page where i have set to create a new plan- new_date.html:
{% extends "meal_plans/base.html" %}
{% block content %}
<p>Add new Date:</p>
<form action="{% url 'meal_plans:new_date' %}">
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Add New Date</button>
</form>
{% endblock content %}
what can i do to the data be inputted in that way
i hope the code here is enough and relevant.
Hello I had similar problem and I found something like this
class DateInput(forms.DateInput):
input_type = 'date'
And then in your modelform
class NewDate(forms.ModelForm):
class Meta:
model = TheDate
widgets = {
'theDate': DateInput()
}
fields = ['theDate']
Put in your forms.py something like this:
class NewDate(forms.ModelForm):
theDate = forms.DateTimeField (
widget=forms.DateTimeInput (
attrs={
'type': 'datetime-local',
}
)
)
class Meta:
model = TheDate
fields = ['theDate']
labels = {'theDate': ''}
This worked here!

Django Form DateInput with widget in update: loosing the initial value

I need a DateInput field in a ModelForm with the default HTML datepicker (I'm not using 3rd party libraries).
Since the DateInput is rendered with <input type = "text"> by default, the datepicker is missing (it comes for free with <input type = "date">)
I've found some examples explaining how to change the input type by handling widget parameters (below the code I've done so far)
The issue
I have the datepicker working correctly but in "update mode" when passing initial date value to the form (see view part), the date remains empty in the HTML.
I've tried to find the cause and it seems that the 'type': 'date' part in the widget customization is clearing the initial value is some way; in fact, removing it, the initial value date is displayed again, but I loose the datepicker of course.
In the view the date is passed with a valid value
I also found another similar unanswered question where the field was declared as
class DateInput(forms.DateInput):
input_type = 'date'
date_effet = forms.DateField(widget=forms.DateInput(format='%d-%m-%Y'), label='Date effet')
the problem still remains
My code
model.py
class TimesheetItem(models.Model):
date = models.DateField()
description = models.CharField(max_length=100)
# many other fields here
form.py
class TimesheetItemForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# init is used for other fields initialization and crispy forms
class Meta:
model = TimesheetItem
fields = ['date', 'description']
widgets = {
'date': forms.DateInput(
format=('%d/%m/%Y'),
attrs={'class': 'form-control',
'placeholder': 'Select a date',
'type': 'date' # <--- IF I REMOVE THIS LINE, THE INITIAL VALUE IS DISPLAYED
}),
}
 view.py
def edit(request, uuid):
try:
timesheet_entry_item = TimesheetItem.objects.get(uuid=uuid)
if request.method == 'POST':
form = TimesheetItemForm(
data=request.POST,
instance=timesheet_entry_item
)
if form.is_valid():
pass # save the form
else:
form = TimesheetItemForm(initial={
'date': timesheet_entry_item.date, # <--- the date here has a valid value
'description': timesheet_entry_item.description
})
return render(request, 'template.html', {'form': form})
except ObjectDoesNotExist:
raise Http404("error")
Thanks for any help
M.
I managed to make it work. Following the cause of the issue, I hope it can be useful to others.
The HTML <input type='date'> element wants a date in the format YYYY-mm-dd; in fact an example of working HTML must be like this:
<input type="date" name="date" value="2020-03-31"
class="form-control dateinput form-control"
placeholder="Select a date" required="" id="id_date">
Since by default the form.DateInput produces the element <input type='text'>, it expects a date in the local format: let's say '31/03/2020'.
Forcing the 'type': 'date' and local format format=('%d/%m/%Y') or not passing a format at all, it ignores the value passed since the <input type='date'> wants format=('%Y-%m-%d')
At last the correct instruction was:
widgets = {
'date': forms.DateInput(
format=('%Y-%m-%d'),
attrs={'class': 'form-control',
'placeholder': 'Select a date',
'type': 'date'
}),
}
Recently, I coded:
date = models.DateTimeField() in models.py
widgets = {'date': NumberInput(attrs={'type': 'date'})} in forms.py
form = <ModelForm>(instance=<model_instance>, data=request.POST) in views.py
and ran into the same problem. I figured it out by changing to:
widgets = {'date': DateInput(attrs={'type': 'date'})} in forms.py.
Maybe how to pre-fill the form matters in views.py. Another difference is , I imported DateInput from django.forms.widgets, not django.forms.

Django Forms - DateInput not populating from instance

I'm trying to set up an edit form for a Django model which includes a DateField. I've set this field as a forms.DateInput in forms.py. This works fine for creating a new instance of the model, but when I try to populate the form with an existing instance the DateInput field remains blank even though all of the other fields are populated correctly.
If I revert to the default TextField input then the data is recalled correctly. I've also tried to set a format in the DateInput widget.
models.py
class Rider(models.Model):
first_name = models.CharField(max_length=40)
surname = models.CharField(max_length=40)
MALE = 'M'
FEMALE = 'F'
GENDER_CHOICES = [
(MALE, 'Male'),
(FEMALE, 'Female'),
]
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
dob = models.DateField("Date of Birth", auto_now = False, auto_now_add = False)
club = models.CharField(max_length=50,blank=True, null=True)
bc_number = models.IntegerField("British Cycling Membership Number", blank=True, null=True)
linked_account = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=1)
views.py
def rider_edit(request, pk):
rider = get_object_or_404(Rider, pk=pk)
if request.method == "POST":
form = RiderForm(request.POST, prefix='rider', instance=rider)
if form.is_valid():
rider = form.save(commit=False)
rider.linked_account = request.user
rider.save()
return redirect('rider_list')
else:
form = RiderForm(prefix='rider', instance=rider)
return render(request, 'riders/rider_new.html', {'riderform': form})
form.py
from django import forms
from .models import Rider, MedicalInfo
class RiderForm(forms.ModelForm):
class Meta:
model = Rider
fields = ('first_name', 'surname', 'gender', 'dob', 'club', 'bc_number')
widgets= {
'dob': forms.DateInput(attrs={'type': 'date'}, format='%d/%m/%Y')
}
rider_new.html
<h2>New Rider</h2>
<form method="POST" class="post-form">
{% csrf_token %}
{{ riderform.as_p }}
<button type="submit" class="save btn btn-default">Add Rider</button>
</form>
The dob field is the only field that doesn't populate correctly from the database, it should show a date in the format dd/mm/YYYY e.g. "10/09/2010". It's actually showing the default "dd/mm/YYYY".
I found a solution to the problem, the date from the database was being returned in "%d/%m/%Y" format but the input on the form was of the "date" type which expects an input in the format "%Y-%m-%d", by changing:
widgets= {
'dob': forms.DateInput(format=('%d/%m/%Y'), attrs={'class':'form-control', 'placeholder':'Select Date','type': 'date'})
}
to:
widgets= {
'dob': forms.DateInput(format=('%Y-%m-%d'), attrs={'class':'form-control', 'placeholder':'Select Date','type': 'date'})
}
Therefore, the generated HTML form changed from:
<input type="date" name="rider-dob" value="10/09/2010" class="form-control" placeholder="Select Date" required="" id="id_rider-dob">
to:
<input type="date" name="rider-dob" value="2010-09-10" class="form-control" placeholder="Select Date" required="" id="id_rider-dob">

Django - Form value ERROR [Simple?]

I will provide all the details necessary to this issue.
Issue description:
I store some input fields with the Django forms (i.e. FormPredmet)
After that I save the form in a model called > Predmet
When pulling the data I have an issue that I didn't have with ModelForm
When printing or displaying (on the page) the Predmet.predavacIme object I get:
<input type="text" name="Ime_Predavaca" value="Elvir" maxlength="50" required id="id_Ime_Predavaca" /> <input type="text" name="Ime_Predavaca" value="Elvir" maxlength="50" required id="id_Ime_Predavaca" /> <input type="text" name="Ime_Predavaca" value="Dzenan" maxlength="50" required id="id_Ime_Predavaca" /> <input type="text" name="Ime_Predavaca" value="Petko" maxlength="50" required id="id_Ime_Predavaca" />
Instead I just wanted a single value of each of these:
Desired output: Elvir,Elvir, Dzenan, Petko
Summary:
I get data using FormPredmet(forms.Form) this is I think the issue
then save the data to the Model Predmet
I try getting any obj for instance: myobj = Predmet.objects.get(pk=1)
after printing one of it's fields print(myobj.imePredavaca())
Instead of a value like "Elvir" I get HTML..input.. (did I store html?)
Modelsmodels.py
class ModelRazred(models.Model):
godina = models.PositiveSmallIntegerField()
brojRazreda = models.PositiveSmallIntegerField()
ime = models.CharField(max_length=50)
prezime = models.CharField(max_length=50)
class Predmet(models.Model):
predavacIme = models.CharField(max_length=50)
predavacPrezime = models.CharField(max_length=50)
imePredmeta = models.CharField(max_length=50)
razred = models.ForeignKey(ModelRazred, on_delete=models.CASCADE)
URLS urls.py
"""urlconf for the base application"""
from django.urls import path
from .views import *
urlpatterns = [
#Base
path('', home, name='home'),
# Stranice
path('dodajrazred/', dodajrazred, name='dodajrazred'),
path('predmeti/<int:razred_id>/', predmetisubmit, name='predmetisubmit'),
path('razred/<int:razred_id>/', detail, name='detail'),
path('predmetisubmit/<int:razred_id>/', predmetisubmit, name='predmetisubmit'),
# Metode
path('predmet_submit/<int:razred_id>/', predmet_submit, name='predmet_submit'),
]
VIEWS views.py
def detail(request, razred_id):
# Funkcija vraca detalje o odredjenom razredu
# i njegove ucenike?
form = FormPredmet()
detaljiRazreda = ModelRazred.objects.get(pk=razred_id)
form.razred = detaljiRazreda
predmeti = Predmet.objects.filter(razred__id = razred_id)
# svi predmeti tog odredjenog razreda
data = {
'form': form,
'predmeti':predmeti,
'razred_id': detaljiRazreda.id,
'ime' : detaljiRazreda.ime,
'prezime': detaljiRazreda.prezime
}
Forms forms.py
from django import forms
from .models import ModelRazred, Predmet
class Razred(forms.ModelForm):
godina = forms.IntegerField()
brojRazreda = forms.IntegerField()
ime = forms.CharField(max_length=50)
prezime = forms.CharField(max_length=50)
class Meta:
model = ModelRazred
fields = ('godina', 'brojRazreda', 'ime', 'prezime')
class FormPredmet(forms.Form):
Ime_Predavaca = forms.CharField(max_length=50)
Prezime_Predavaca = forms.CharField(max_length=50)
Ime_Predmeta = forms.CharField(max_length=50)
class Meta:
model = Predmet
fields = ('Ime_Predavaca', 'Prezime_Predavaca',
'Ime_Predmeta', 'razred')
def save(self, razredID):
razredPredmeta = ModelRazred.objects.get(pk=razredID)
myModel = Predmet(predavacIme=self['Ime_Predavaca'],
predavacPrezime=self['Prezime_Predavaca'],
imePredmeta=self['Ime_Predmeta'], razred=razredPredmeta)
myModel.save()
You have to clean form data before you save it into the model. Form returns all data with HTML tags. You can check more in the docs. In your case you need to do something like this:
def save(self, razredID):
razredPredmeta = ModelRazred.objects.get(pk=razredID)
myModel = Predmet(predavacIme=self.cleaned_data['Ime_Predavaca'],
predavacPrezime=self.cleaned_data['Prezime_Predavaca'],
imePredmeta=self.cleaned_data['Ime_Predmeta'], razred=razredPredmeta)
myModel.save()
Also I would recommend to move a save() method from your Form to your View - it is more readable to save models there, forms only process form data.

Django forms extra empty radio button

In rendering a model form an extra radio button is produced and I don't know where it's coming from:
>>> f = DocumentForm()
>>> print f['document_type']
<ul id="id_document_type">
<li><label for="id_document_type_0"><input checked="checked" id="id_document_type_0" name="document_type" type="radio" value="" /> ---------</label></li>
<li><label for="id_document_type_1"><input id="id_document_type_1" name="document_type" type="radio" value="1" /> Campus LAN</label></li>
<li><label for="id_document_type_2"><input id="id_document_type_2" name="document_type" type="radio" value="2" /> WAN</label></li>
<li><label for="id_document_type_3"><input id="id_document_type_3" name="document_type" type="radio" value="3" /> UC</label></li>
</ul>
That first radio button with value="" and the text as ---------, I've scoured my code and can't work out where it originates from?
models.py
class DocumentType(models.Model):
name = models.CharField("Document Type", max_length=240)
class Document(models.Model):
document_type = models.ForeignKey(DocumentType,
verbose_name="Document Type")
>>> DocumentType.objects.all()
[<DocumentType: Campus LAN>, <DocumentType: WAN>, <DocumentType: UC>]
>>> d = Document.objects.all()
>>> for x in d:
... print x.document_type
...
Campus LAN
Campus LAN
template:
<form role="form" action="" method="POST">{% csrf_token %}
{{ form.as_p}}
<input type="submit" value="Save" />
</form>
forms.py:
class DocumentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DocumentForm, self).__init__(*args, **kwargs)
self.fields['sections'].queryset = Section.objects.filter(associated_document="Original Section")
self.fields['document_type'].queryset = DocumentType.objects.all()
class Meta:
model = Document
fields = ('customer', 'title', 'document_type', 'sections',)
widgets = {
'sections': forms.widgets.CheckboxSelectMultiple,
'document_type': forms.widgets.RadioSelect,
}
views.py
def new_lld(request):
if request.method == "POST":
form = DocumentForm(request.POST)
if form.is_valid():
document = form.save(commit=False)
document.author = request.user
document.save()
form.save_m2m()
return redirect('lld:index')
else:
form = DocumentForm()
return render(request, 'lld/new_lld.html', {'form': form})
admin.py
class DocumentAdmin(admin.ModelAdmin):
fieldsets = [
('Document Info', {'fields': ['author', 'customer', 'title',
'slug']}),
('Document Type', {'fields': ['document_type', 'sections']}),
]
inlines = [VersionInline]
prepopulated_fields = {"slug": ("customer", "title",)}
list_display = ('title', 'customer', 'author', 'document_type',
'date_created', 'date_updated')
list_filter = ['date_updated', 'author']
Here we go:
https://docs.djangoproject.com/en/dev/ref/forms/fields/#django.forms.ModelChoiceField.empty_label
from here:
Django CheckboxSelectMultiple widget adds --------- value to query set
therefore:
self.fields['document_type'].empty_label = None
does the trick.
A work around is to hide it with css:
#id_document_type li:first-child {display:none}
As Agustin mentioned, ModelChoiceFields must be set to required in order to remove the blank choice.
def __init__(self, queryset, empty_label="---------",
required=True, widget=None, label=None, initial=None,
help_text='', to_field_name=None, limit_choices_to=None,
*args, **kwargs):
if required and (initial is not None):
self.empty_label = None
else:
self.empty_label = empty_label
Required is set to False by default, so you'll need to add the following to your init in Document Form
self.fields['document_type'].required=True
Django has to have a way to allow None values to be set for nullable fields (fields with required=False) and does so by appending an option with an empty value. The same thing happens with Select elements.
Now, for Django to add that option to your Form the document_type field must be nullable (indeed have required=False), and I can only assume that somewhere in the definition of the Form you're setting that option to the field.
PS: If the form is generated automatically for the Model (i.e. you're using Django's ModelForm) then the model should have said Field set with blank=True, null=True, yet that is clearly missing. ModelForm rocks, though, so if you're not familiar with it, try it out.
UPDATE:
TBH I can't work out why that's nullable either, but try setting required=True manually in the form in the same way that #Alistair specified.
self.fields['document_type'].required = True
Right under the line where you modified that field to set the queryset. I think that should work.
I solved this by adding these parameters to my declaration of my field in my model:
blank=False, default=None
So in this case, you model would look like this:
document_type = models.ForeignKey(DocumentType,
verbose_name="Document Type", blank=False, default=None)

Categories