Datetime Validation Error using datetime-local - python

I am trying to render basic HTML template that would allow me to input a date-time values into database using datetime-local input type. However every time I try to enter a value it always return the Enter a valid date/time error
models.py
class AirframeOperation(models.Model):
id = models.AutoField(primary_key=True)
takeoff = models.DateTimeField()
landing = models.DateTimeField()
flight_time = models.DurationField()
metadata = models.OneToOneField(
Metadata,
on_delete=models.CASCADE
)
def save(self, *args, **kwargs):
self.block_time = self.block_on - self.block_off
self.flight_time = self.landing - self.takeoff
return super(AirframeOperation, self).save(*args, **kwargs)
forms.py
class InsertAirframeOperation(forms.ModelForm):
takeoff = forms.DateTimeField(
input_formats=['%d-%m-%YT%H:%M'],
widget=forms.DateTimeInput(
attrs={
'type': 'datetime-local',
'class': 'form-control'
},
format='%d-%m-%YT%H:%M')
)
landing = forms.DateTimeField(
input_formats=['%d-%m-%YT%H:%M'],
widget=forms.DateTimeInput(
attrs={
'type': 'datetime-local',
'class': 'form-control'
},
format='%d-%m-%YT%H:%M')
)
class Meta:
model = AirframeOperation
fields = ['takeoff', 'landing']
widgets = {}
views.py
#login_required(login_url='/accounts/login/')
def dataentry(request):
if request.method == 'POST':
form_meta = forms.InsertMetadata(request.POST)
form_airframe = forms.InsertAirframeOperation(request.POST)
print(form_airframe.errors)
metadata = None
if form_meta.is_valid():
metadata = form_meta.save(commit=False)
metadata.save()
meta_id = metadata.id
print(meta_id)
metadata = Metadata.objects.get(id=meta_id)
if form_airframe.is_valid():
airframe = form_airframe.save(commit=False)
airframe.metadata = metadata
airframe.save()
return redirect('/')
else:
form_meta = forms.InsertMetadata()
form_airframe = forms.InsertAirframeOperation()
return render(request, "dashboard/data_entry.html", {'form': form_meta, 'form2': form_airframe})
data_entry.html
{% extends "base.html" %}
{% block content %}
<div id="data_entry_container">
<h3>Metadata General</h3>
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.errors }}</p>
<p>{{ form.non_field_errors }}</p>
{{ form.as_p }}
<h3>Airframe Operation Metadata</h3>
<p>{{ form2.errors }}</p>
<p>{{ form2.non_field_errors }}</p>
{{ form2.as_p }}
<input type="submit" value="Save">
</form>
</div>
{% endblock content %}
I've tried looking up on the documentations as well as trying out solutions listed here yet it still isn't validating correctly

Instead of declaring the "input_formats" on the field itself, try declaring it on the init.
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["takeoff"].input_formats = ["%Y-%m-%dT%H:%M"]
I've been scratching my head on this same problem for about an hour now, and nothing seems to work except this.
It should be noted that as stated in the documentation (https://docs.djangoproject.com/en/3.0/ref/forms/fields/), the DateTimeField should accept an optional argument "input_formats". But as to why it's not working, I have no idea.
If someone can explain this issue better than I, please do.

Related

Form not submitting to the DataBase when using HTMX

I have the following models, and as you can see they are related to each other
class Leads(models.Model):
project_id = models.BigAutoField(primary_key=True, serialize=False)
created_at = models.DateTimeField(auto_now_add=True)
expected_revenue = MoneyField(decimal_places=2,max_digits=14, default_currency='USD')
expected_licenses = models.IntegerField()
country = CountryField(blank_label='(select_country)')
status = models.CharField(choices=[('Open', 'Open'), ('Closed', 'Closed'), ('Canceled', 'Canceled'),
('Idle', 'Idle')
], max_length=10)
estimated_closing_date = models.DateField()
services = models.CharField(choices=[('Illumination Studies', 'Illumination Studies'),
('Training', 'Training'),('Survey Design Consultancy', 'Survey Design Consultancy'),
('Software License', 'Software License'),
('Software Development','Software Development')], max_length=40)
agent = models.ForeignKey(Profile, default='agent',on_delete=models.CASCADE)
company = models.ForeignKey(Company,on_delete=models.CASCADE)
point_of_contact = models.ForeignKey(Client, default='agent',on_delete=models.CASCADE)
updated_at = models.DateTimeField(auto_now=True)
application = models.CharField(choices=[('O&G','O&G'),('Renewables','Renewables'),('Mining','Mining'),
('Other','Other'),('CSS','CSS')],
default='O&G',max_length=20)
sub_category = models.CharField(choices=[('Wind','Wind'),('Geo-Thermal','Geo-Thermal'),('Solar','Solar'),
('Tidal','Tidal')], max_length=20, blank=True)
#property
def age_in_days(self):
today = date.today()
result = self.estimated_closing_date - today
return result.days
def __str__(self):
return f'{self.project_id}'
class LeadEntry(models.Model):
revenue = MoneyField(decimal_places=2,max_digits=14, default_currency='USD',blank=True)
date = models.DateField()
lead_id = models.ForeignKey(Leads,on_delete=models.CASCADE)
id = models.BigAutoField(primary_key=True, serialize=False)
probability = models.DecimalField(max_digits=2, decimal_places=2, default=0, blank=True)
#property
def est_revenue(self):
result = self.revenue * probabiity
return result
Essentially a lead entry is related to the lead, and I'm using HTMX to essentially add data to LeadEntry database using a form.
Form
class LeadEntryForm(forms.ModelForm):
class Meta:
model = LeadEntry
fields = ('lead_id','date','revenue','probability')
widgets = {'date': DateInput()}
I have 2 views, one that will simply pass an HTML with a button for the user to add entries to the database, and another view with the actual form
views
#login_required
def add_to_forecast(request):
id = request.GET.get('project_id')
request.session['lead_id'] = id
return render(request, 'account/lead_forecast.html')
#login_required
def forecast_form(request):
if request.method=='POST':
form = LeadEntryForm(data=request.POST or None)
if form.is_valid():
form.save(commit=False)
messages.success(request,"Successful Submission")
return redirect('add_to_forecast')
lead_id = request.session['lead_id']
data = {'lead_id':lead_id}
context = {
"form":LeadEntryForm(initial=data)
}
return render(request, 'account/lead_entry_forecast.html', context)
Lastly, there are 2 HTML pages, the first one is associated with add_to_forecast and renders a simple page, this is where the HTMX happens and this adds the form from the next HTML page
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load static %}
{% block title %}Client Information {% endblock %}
{% block content %}
<h1> Add Lead to Sales Forecast </h1>
<p>Click the Button below to add a Payment Date</p>
<button type="button" hx-get="{% url 'lead_entry_forecast' %}" hx-target="#leadform" hx-swap="beforeend" >
Add Lead </button>
<div id="leadform">
<br>
</div>
{% endblock %}
The form that is added by the user as many times they want to do so
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<div class="container-fluid">
<form method="post" enctype="multipart/form-data" action=".">
{% csrf_token %}
<div class="row justify-content-center">
<div class="col-sm-1">
{{ form.lead_id|as_crispy_field }}
</div>
<div class="col-sm-2">
{{ form.date|as_crispy_field }}
</div>
<div class="col-sm-2">
{{ form.revenue|as_crispy_field }}
</div>
<div class="col-sm-1">
{{ form.probability|as_crispy_field }}
</div>
<div class="col-sm">
<input type="submit" value="Submit" >
</div>
</div>
</form>
</div>
<hr>
{% endblock %}
The problem I have is that after submitting the form, everything seems to be working, obviously, at the moment you can only submit one lead, as I still have to add more logic, but at the moment the form is not sending data to the DB, after some debugging, I was not able to pass the POST, it seems like is just not submitting anything.
Any help will be highly appreciated
Update - 12/4/2021
I have tried to submit data using the form and it actually works, so there is nothing wrong with the form submitted the POST.request, if I go directly to the URL, it works fine, so the form is submitted correctly and the database is updated.
I still don't understand why is not working when the form is rendered by the htmx, so it has something to do with that.
When you are designing an HTMX page, you have to be careful with the post request, so I was processing the form in the wrong view, please see below the views:
#login_required
def add_to_forecast(request):
form = LeadEntryForm(data=request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
return HttpResponse("Success")
else:
return render(request, 'account/lead_entry_forecast.html', {"form": form})
id = request.GET.get('project_id')
request.session['lead_id'] = id
return render(request, 'account/lead_forecast.html')
#login_required
def forecast_form(request):
lead_id = request.session['lead_id']
data = {'lead_id':lead_id}
context = {
"form":LeadEntryForm(initial=data)
}
return render(request, 'account/lead_entry_forecast.html', context)
Now it works as it should

How to assign model fields to a custom variable in the view, and use it in context to pass to the template?

so I have a model in models.py, and it has a few fields. Next, I make a form in forms.py to make a creative form. Then I import that form from forms.py into views.py. In the views.py, I make the create view, with the creat form. But here's the problem. In the views.py, I have the model field space. now I want to do something with that field. I assign a custom variable to this space field and pass it in the context.
But it gives an error called local variable not defined.
models.py
class NewJax(models.Model):
title = models.CharField(max_length=60)
description = models.TextField(max_length=140)
space = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_created = models.DateTimeField(default=timezone.now)
class Meta:
ordering = ['-date_created']
verbose_name_plural = "New Jax"
def __str__(self):
return str(self.title)
forms.py
class CreateNewJaxForm(forms.ModelForm):
class Meta:
model = NewJax
fields = ('title', 'description', 'space')
widgets = {
"title": forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'name your jax'
}
),
'description': forms.Textarea(
attrs={
'class': 'form-control',
'placeholder': 'add a brief description for jax',
'rows': 4,
}
),
'space': forms.Textarea(
attrs={
'class': 'form-control',
}
)
}
views.py
def create_new_jax(request):
if request.user.username == "Assasinator":
logout(request)
return redirect('banned_user')
if request.method == "POST":
form = CreateNewJaxForm(request.POST or None)
if form.is_valid():
title = form.cleaned_data.get('title')
description = form.cleaned_data.get('description')
space = form.cleaned_data.get('space')
result = exec(space) # I AM TRYING TO SPECIFY THIS CUSTOM VARIABLE IN CONTEXT
obj = form.save(commit=False)
obj.title = title
obj.description = description
obj.space = space
obj.user = request.user
obj.save()
return redirect('/create_new_jax/')
else:
form = CreateNewJaxForm()
else:
form = CreateNewJaxForm()
context = {
"form": form,
"result": result, # HERE, I PASS IT IN CONTEXT
}
return render(request, "editor/jax_create.html", context)
so as you see, I made a custom variable result. And I specify it to the space variable from the NewJax model.
Now when I run this, it gives the error.
So if someone could tell me how to pass this variable into context, I would appreciate it.
Thanks!
now, if this is solved, i also want the code to execute. That's what exec does. So when i print result in my template, it needs to show the output of space.
html file
{% extends 'editor/base.html' %}
{% load crispy_forms_tags %}
{% block title %}
<title>Jax | Create New Jax</title>
{% endblock %}
{% block content %}
{% if user.is_authenticated %}
<h1>Create A New Jax</h1>
<br><br>
{{ result }}
<form method="POST"> {% csrf_token %}
{{ form|crispy }} <br>
<button class="btn btn-primary">Run</button>
</form>
<br><br>
{% else %}
<div class="alert alert-danger" role="alert">
<h2 class="alert-heading">You are not allowed here</h2>
<p>Go back to the homepage, and login in, or register if you don't have an account. Then you can do what you were doing now.</p>
<hr>
<p type="button" class="btn btn-danger">Go back to home page</p>
</div>
{% endif %}
{% endblock %}
so when i click run, it needs to show the output where i put the {{ result }}
please let me know this. Thanks!
def create_new_jax(request):
if request.user.username == "Assasinator":
logout(request)
return redirect('banned_user')
result = None
if request.method == "POST":
form = CreateNewJaxForm(request.POST or None)
if form.is_valid():
title = form.cleaned_data.get('title')
description = form.cleaned_data.get('description')
space = form.cleaned_data.get('space')
result = exec(
space) # I AM TRYING TO SPECIFY THIS CUSTOM VARIABLE IN CONTEXT
obj = form.save(commit=False)
obj.title = title
obj.description = description
obj.space = space
obj.user = request.user
obj.save()
return redirect('/create_new_jax/')
else:
form = CreateNewJaxForm()
else:
form = CreateNewJaxForm()
context = {
"form": form,
"result": result, # HERE, I PASS IT IN CONTEXT
}
return render(request, "editor/jax_create.html", context)
result variable was defined in if scope. So it was local to if function. So define the variable result for overall function with default value. i.e None, empty list or dict.

Problem setting initial Django ModelForm field value

I’m trying to set the default value in the form (the field is the date for publishing the article “public”), but when loading the form on the page, the field is empty. I tried to set the default value in the "header" field (any value, not necessarily today's date) - also does not appear.
form:
from main.models import Article
from datetime import datetime
class AddArticleForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddArticleForm, self).__init__(*args, **kwargs)
self.fields['publish'].initial = datetime.now()
class Meta:
model = Article
fields = ('title', 'author', 'body', 'publish', 'status')
labels = {
'body': 'Text'
}
widgets = {
'title': forms.TextInput(attrs={'class': 'md-form'}),
'author': forms.TextInput(attrs={'class': 'md-form'}),
'body': forms.Textarea(attrs={'class': 'md-textarea', 'rows': 3}),
'publish': forms.DateTimeInput(attrs={'class': 'md-form'}),
'status': forms.Select(attrs={'class': 'custom-select'})
}
views:
def add_article(request):
form = AddArticleForm(request.POST)
if form.is_valid():
form.save()
return redirect('/articles/')
args = {
'form': form
}
return render(request, 'html/add_article.html', args)
html:
...
<form action="." method="post" class="add-article">
{% csrf_token %}
{% for field in form %}
<div class="md-form">
{% if field.name != 'status' and field.name != 'publish' %}
<label for="{{ field.name }}">{{ field.label }}</label> {{ field }}
{% else %}
<label for="{{ field.name }}"></label> {{ field }}
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-pink btn-block">Share</button>
</form>
...
Probably the issue is you are sending request.POST as argument to the form class even if it is a GET request.
form = AddArticleForm(request.POST)
^^^^^^^^^^^^^
So I suggest to update the view like this:
def add_article(request):
form = AddArticleForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('/articles/')
context = {
'form': form
}
return render(request, 'html/add_article.html', context)
So that, it will handle POST requests explicitly, and send request.POST as argument only if there is request.POST.
I think you should add initial argument in your field form.
For example:
name = forms.CharField(initial='Your name')
Here is documentation on this:
https://docs.djangoproject.com/en/3.0/ref/forms/fields/#initial

Django - objects.all() shows nothing

I'm trying to get a list of objects in Django from a model.
I just want to get the list of 'dht node' from the request user, but it shows nothing in the html file (as if the list was empty). The user that I'm using has 2 'dht nodes' and they're shown in the django admin.
I don't know what is wrong, because if I use the instruction "member.dht.create(...)" in the views function and a create a new 'dht node' like this, this is shown. Only 'dht nodes' that I enter by form do not show. Can be the form?
Thanks a lot, Here's my code:
Models.py
class Node(models.Model):
name = models.CharField(primary_key=True, null=False, max_length= 50)
description= models.CharField(default=None, null=False, max_length= 250)
topic=models.CharField(default=None, null=False, max_length= 50, unique=True)
def __unicode__(self):
return self.name
class dht(Node):
temp = models.IntegerField(default=None, null=True)
hum = models.IntegerField(default=None, null=True)
class UserProfile(User):
uid = models.CharField(default=None, null=False, max_length= 250)
dht = models.ManyToManyField(dht, blank=True)
def __unicode__(self):
return self.user.username
Views.py -dht list-
#login_required(login_url = '/web/login')
def listDhtSensor(request):
member = request.user.userprofile
list = member.dht.all()
return render(request, 'web/listDhtSensor.html', {'list':list})
Html -listDhtSensor.html-
{% block content %}
{% for dht in list %}
{{ dht.name }}
{{ dht.topic }}
{% endfor %}
{% endblock %}
Forms.py
class newDHTSensorForm(forms.ModelForm):
class Meta:
model = dht
field = ['name',
'description',
'topic',]
labels = {'name': 'Name' ,
'description': 'Description',
'topic': 'Topic',}
exclude = ['temp', 'hum']
Views.py -dht form-
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Html -newDhtSensor.html-
{% block content %}
<div class="boxReg">
<form method="post">
{% csrf_token %}
<h2>{{ form.name.errors.as_text }}</h2>
<p><label for="id_name">Name:</label> <input class="barraForm" type="text" name="name" maxlength="150" autofocus="" required="" id="id_name"></p>
<p><label for="id_description">Description:</label> <input class="barraForm" type="text" name="description" maxlength="150" id="id_description"></p>
<h2>{{ form.topic.errors.as_text }}</h2>
<p><label for="id_topic">Topic:</label> <input class="barraForm" type="text" name="topic" maxlength="254" id="id_topic"></p>
<div class="boxButtonReg">
<button class="buttonReg" type="submit">Save</button>
</div>
</form>
</div>
{% endblock %}
It shows nothing because you did not link you dht objects to that UserProfile, so if you later query for the dhts for that UserProfile, evidently the list is empty. You should add it to the dht relation, like:
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save()
request.user.userprofile.dht.add(post)
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Note that you first need to save the post, so you should omit the commit=False aprameter.

Django Form Field not showing up

I just started learning Django and for this project I'm following the "Tango with Django" tutorial book. I have a problem with the input field of a form not showing up, while the button seems to be rendered fine.
Here's my code:
models.py
[...]
class Idea(models.Model):
keyword = models.ForeignKey(Keyword)
word = models.CharField(max_length=120)
count = models.IntegerField(default=1)
def __str__(self):
return self.word
forms.py
[...]
class Meta:
model = Keyword
fields = ('name',)
class IdeaForm(forms.ModelForm):
word = forms.CharField(max_length=120)
count = forms.IntegerField(widget=forms.HiddenInput(), initial=1)
class Meta:
model = Idea
fields = ('word',)
exclude = ('keyword',)
views.py
[...]
def keyword_detail(request, keyword_name_slug):
form = IdeaForm()
context_dict = {}
try:
keyword = Keyword.objects.get(slug=keyword_name_slug)
ideas = Idea.objects.filter(keyword=keyword)
context_dict['keyword'] = keyword
context_dict['ideas'] = ideas
except Keyword.DoesNotExist:
context_dict['keyword'] = None
context_dict['ideas'] = None
if request.method == 'POST':
form = IdeaForm(request.POST)
if form.is_valid():
idea = form.save(commit=False)
idea.keyword = keyword
idea.count = 1
idea.save()
return keyword_detail(request, keyword_name_slug)
else:
print(form.errors)
context_dict['form'] = form
return render(request, 'openminds/keyword.html', context_dict)
keyword.html
[...]
<h3>Add a new Idea</h3>
<div>
<form id="idea_form" method="post" action="">{% csrf_token %}
{% for hidden in forms.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in forms.visible_fields %}
{{ field.errors }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Add Idea" />
</form>
</div>
I think you're passing in form to the template, but attempting to use forms.

Categories