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
Related
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.
I have the modelform
class CollectionForm(forms.ModelForm):
Medicine_Name = forms.ModelChoiceField(queryset=Medicine.objects.all())
class Meta:
model = Medicine
fields = ['Number_Of_Boxes', 'Last_Collected']
def __init__(self, user = None, *args, **kwargs):
super().__init__(*args, **kwargs)
if user:
self.fields['Medicine_Name'].queryset=Medicine.objects.filter(User_Associated=user)
And the view to handle the form:
def update(request, *args, **kwargs):
if request.method == 'POST':
qd = request.POST['chosen_medicine']
instance = Medicine.objects.get(id=qd)
form = CollectionForm(request.POST, instance=instance)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
form = CollectionForm()
context = {'form': form,
'meds': Medicine.objects.filter(User_Associated=request.user),
}
return render(request, 'tracker/medicine_collection.html', context )
The template for the form is here:
<form method="POST" action = ''>
{% csrf_token %}
<label for="Medicine_Name">Medicine Name</label>
<select class = "form-control" id = "Medicine_Name" name = "chosen_medicine">
{% for med in meds %}
<option value = '{{med.auto_id}}'>{{ med.Medicine_Name }}</option>
{% endfor %}
</select>
{{form.Number_Of_Boxes }}
{{form.Last_Collected }}
<button class="btn btn-outline-info" type="submit">Create</button>
</form>
I am trying to get the id of the Medicine_Name which the user chooses from the dropdown list. To do this I have a POST request in my view to get the id. However, when submitting my form I get the error:
Field 'id' expected a number but got <QueryDict: {'csrfmiddlewaretoken': ['rrkPEpuZqxWQ9TS4lLMRDwAQ7xZAOUVZl8iHLVfZJ8gEfKundDMvDh9oWp42l1Jf'], 'chosen_medicine': ['1'], 'Number_Of_Boxes': ['3'], 'Last_Collected': ['03/16/2020']}>.
How can I make sure the POST request actually gets the ID, not a querydict which contains all the fields of my form?
You can define the constructor such that the positional parameters are still preserved:
class CollectionForm(forms.ModelForm):
class Meta:
model = Medicine
fields = ['Number_Of_Boxes', 'Last_Collected']
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
if user:
self.fields['Medicine_Name'].queryset=Medicine.objects.filter(
User_Associated=user
)
In the view you then pass the user as a named parameter:
def update(request, *args, **kwargs):
if request.method == 'POST':
qd = request.POST['chosen_medicine']
instance = Medicine.objects.get(id=qd)
form = CollectionForm(request.POST, instance=instance, user=request.user)
if form.is_valid():
instance = form.save()
else:
form = CollectionForm(user=request.user)
context = {'form': form,
'meds': Medicine.objects.filter(User_Associated=request.user),
}
return render(request, 'tracker/medicine_collection.html', context)
The HTML also looks "odd", especially the spacing around attributes:
<form method="POST" action="">
{% csrf_token %}
<label for="Medicine_Name">Medicine Name</label>
<select class="form-control" id="Medicine_Name" name="chosen_medicine">
{% for med in meds %}
<option value="{{ med.id }}">{{ med.Medicine_Name }}</option>
{% endfor %}
</select>
{{ form.Number_Of_Boxes }}
{{ form.Last_Collected }}
<button class="btn btn-outline-info" type="submit">Create</button>
</form>
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
Something quick and messy could work.
data = dict(qd.iterlists())
instance = Medicine.objects.get(id=int(data.get('chosen_medicine')[0]))
But in my opinion you should not even post a whole queryset if all you need is a single id.
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.
The submit button doesn't work.
Can't save in database
{% block content %}
<form class="" action="{% url 'post_create_url' %}" method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
{% if field.errors %}
<div class="alert alert-danger">
{{ field.errors }}
</div>
{% endif %}
{{ field.label }}
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Create Post</button>
</form>
{% endblock %}
this is my views.py code
class PostCreate(View):
def get(self, request):
form = PostForm()
return render(request, 'blog/post_create_form.html', context={'form': form})
def post(self, request):
bound_form = PostForm(request.POST)
if bound_form.is_valid():
new_post = bound_form.save()
return redirect(new_post)
return render(request, 'blog/post_create_form.html', context={'form': bound_form})
and this is my form code
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'body', 'tags']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'slug': forms.TextInput(attrs={'class': 'form-control'}),
'body': forms.Textarea(attrs={'class': 'form-control'}),
'tags': forms.SelectMultiple(attrs={'class': 'form-control'}),
}
def clean_slug(self):
new_slug = self.cleaned_data['slug'].lower()
if new_slug == 'create':
raise ValidationError('Slug may not be "Create"')
return new_slug`
class PostCreate(View):
def get(self, request):
form = PostForm()
return render(request, 'blog/post_create_form.html', context={'form': form})
def post(self, request):
bound_form = PostForm(request.POST)
if bound_form.is_valid():
### new_post = bound_form.save() That's the problem.
bound_form.save()
###return redirect(new_post)
return HttpResponseRedirect('new_post')
return render(request, 'blog/post_create_form.html', context={'form': bound_form})
I have created some custom error message following the documentation (as best as I can find) but I'm not getting any errors, let alone my custom errors. Here's my code:
forms.py
class UploadFileForm(forms.ModelForm):
class Meta:
model = Job
fields = ['jobID','original_file']
labels = {
'jobID': _('Job ID'),
'original_file': _('File'),
}
error_messages = {
'jobID': {
'max_length': _("Job ID is limited to 50 characters."),
'required': _("Please provide a Job ID."),
'invalid': _("Job ID must be a combination of letters, numbers, - and _.")
},
'original_file': {
'required': _("Please provide a file."),
'validators': _("Please ensure you are selecting a zipped (.zip) GDB."),
},
}
help_texts = {
'original_file': _('Please provide a zipped (.zip) GDB.'),
}
upload.html
<form method = "POST" action="{% url 'precheck:upload' %}" enctype="multipart/form-data" name="uploadForm">
{% csrf_token %}
{% for field in form %}
<div>
<strong>{{ field.errors }}</strong>
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class ="help-text">{{ field.help_text }}</p>
{% endif %}
</div>
{% endfor %}
<br />
<button type="button" id="uploadButton" data-loading-text="Loading..." class="btn btn-primary" autocomplete="off" style="margin: auto 20%; ">Upload</button>
</form>
views.py
def upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, user = request.user)
if form.is_valid():
form.save()
request.session['jobID'] = request.POST['jobID']
#job = Job.objects.filter(user_id = request.user.id).filter(jobID = request.POST['jobID']).latest()
# initialize(job)
return render(request,'precheck/run_precheck.html')
form = UploadFileForm()
historyList = Job.objects.filter(user_id = request.user.id)[:10]
return render(request, 'precheck/upload.html',{'form': form, 'history': historyList})
I've included everything I think is relevant, let me know if you need anything more.
The problem is that if the form is not valid, you're resetting the form to the initial form:
form = UploadFileForm()
historyList = Job.objects.filter(user_id = request.user.id)[:10]
return render(request, 'precheck/upload.html',{'form': form, 'history': historyList})
Your flow should render the bound form (with its errors) so it should be:
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, user = request.user)
if form.is_valid():
# do stuff for valid form
return redirect
elif request.method == 'GET':
form = UploadFileForm()
# flow common for GET and invalid form
return render(request, template, {'form': form})