I'm building a simple web app where users can log new entries that have a name (CharField) and a date.
By default, the date is set to the current date:
class EntryForm(forms.Form):
entry_name = forms.CharField(label='New Entry', max_length=100)
entry_date = forms.DateField(initial=datetime.date.today, widget=forms.widgets.DateInput(attrs={'type': 'date'}))
If users select a different date and add an entry with that date, I want the selected date to persist as new initial value when the page reloads.
I know there are a lot of related questions on setting initial values dynamically, but unfortunately, I still could achieve setting an initial value dynamically.
My view with the form looks like this:
#login_required
def index(request):
if request.method == 'POST':
form = EntryForm(request.POST)
if form.is_valid():
# get the label name and strip and convert to lower before saving it
entry_name = form.cleaned_data['entry_name'].strip().lower()
entry_date = form.cleaned_data['entry_date']
entry = Entry.objects.create(name=entry_name, date=entry_date, owner=request.user)
return HttpResponseRedirect(reverse('app:index'))
else:
form = EntryForm()
# other, unrelated stuff stuff ...
context = {
'form': form,
}
return render(request, 'app/index.html', context)
Even setting the initial value of a form field to a fixed value inside the view's else branch didn't work. I tried EntryForm(initial={'entry_name': 'test'}) (also for entry_date) without success. Also form.fields['entry_name'].initial = 'test', which didn't work either. In both cases, the from's entry_name remained empty when reloading the page.
What's the problem? How can I set the initial value in the form (neither for name nor for date)?
Is it somehow because the form is still unbounded?
If setting the initial value in the view worked, I think I could simply set it when the date is entered and it should stay when the page is reloaded since I pass the form (with the adjusted initial value) in the context dict when rerendering the page.
Edit: This is how I render my form in the template:
<div class="input-group">
<input type="text" class="form-control" id="{{ form.entry_name.id_for_label }}" name="{{ form.entry_name.html_name }}" aria-label="new entry field">
{{ form.entry_date }}
<div class="input-group-append">
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
Oh, I think I didn't test correctly. In fact, setting
form = EntryForm(initial={'entry_date': '2020-12-12'})
inside my view does work fine and the date gets initialized as configured.
I guess, I just tried passing a datetime.date before or tested with initializing entry_name, but that didn't work because of how I render entry_name in the template.
To persist the previously entered date, I added an optional argument init_date to my index view, which is set according to the previously entered date:
def index(request, init_date=datetime.date.today()):
if request.method == 'POST':
form = EntryForm(request.POST)
if form.is_valid():
entry_name = form.cleaned_data['entry_name'].strip().lower()
entry_date = form.cleaned_data['entry_date']
entry = Entry.objects.create(name=entry_name, date=entry_date, owner=request.user)
return HttpResponseRedirect(reverse('app:index_with_date', args=[entry_date]))
else:
form = EntryForm(initial={'entry_date': init_date})
For that, I added another URL pattern:
path('add/<entry_name>/<yyyymmdd:entry_date>/', views.add_entry, name='add_entry_with_date'),
With the following date converter:
class DateConverter:
regex = '\d{4}-\d{2}-\d{2}'
def to_python(self, value):
return datetime.datetime.strptime(value, '%Y-%m-%d')
def to_url(self, value):
return value
register_converter(DateConverter, 'yyyymmdd')
Related
I have a Django form NameForm. I am attempting to iterate over an array of values and, for each value, have an option to display the same form. The only thing that should change with the form submission should be the associated value to which the form is displayed next to.
This becomes much clearer with an example. For some array [1,2,3] we should display:
We can then click on any open form icon, fill out the NameForm form. The resultant information, including the form_id (in this case 1, 2, or 3) should be returned to forms.py. How can I fetch the form_id variable from an instance of NameForm in index.py?
My (hacky) attempt can be found below. The problem is I don't know how to access the form_id variable I created in the NameForm object.
forms.py
class NameForm(forms.Form):
form_id = None
your_name = forms.CharField(label='Your name', max_length=3)
views.py
def index(request):
if request.method == 'POST':
form = NameForm(request.POST)
form_id = form.form_id # The problem line, as form_id is always None
if form.is_valid():
return HttpResponse( \
' '.join((str(form.cleaned_data['your_name']),form_id ))\
) #Throws TypeError as can't join None and string
else:
forms = []
vals = [1,2,3]
for val in vals:
form = NameForm()
form.form_id = val
forms.append(form)
return render(request, 'post/index.html', {'forms': forms})
index.html
{%for form in forms%}
{{form.form_id}}
<button class="button" onclick="openForm()">Open Form</button>
<div class="myForm">
<form class="form-container" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
<button class="button" onclick="closeForm()">Cancel</button>
</form>
</div>
</br>
{%endfor%}
In Django Form or Django Model, when you set a field's value to None, it is assumed that you want to ignore said field. This is helpful when creating a model that inherits from another model and you want to remove some unnecessary fields.
If you want to set value for a field on Form creation, you should pass it into __init__ method. E.g:
class NameForm(forms.Form):
form_id = forms.IntegerField(widget=forms.HiddenInput())
your_name = forms.CharField(label='Your name', max_length=3)
def __init__(self, form_id, *args, **kwargs):
self.fields['form_id'].initial = form_id
Alternatively, instead of overriding the __init__ method, you can set an initial value for form_id when you create an instance of NameForm. For example:
vals = [1,2,3]
forms = [NameForm(initial={'form_id': val}) for val in vals]
I am using a filter and .aggregate to sum up the value of a column cases in my Manifests model. When this displays in the template it gives me the correct amount, but when the page displays it shows as, for example, {'cases__sum': 1192}. The number 1192 there is indeed the sum, but I don't want the rest of the text to show to the user! How can I stop this and get just the number?
views.py
def add_manifest(request, reference_id):
form = CreateManifestForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
instance = form.save(commit=False)
try:
order = Orders.objects.get(id=reference_id)
instance.reference = order
except Orders.DoesNotExist:
pass
instance.save()
form = CreateManifestForm(initial={'reference': Orders.objects.get(reference=reference_id)})
reference = request.POST.get('reference')
manifests = Manifests.objects.all().filter(reference=reference)
total_cases = Manifests.objects.filter(reference=reference).aggregate(Sum('cases')) #totaling the cases for the readonly field
totalCNF = 0
for item in manifests:
totalCNF += item.cases * item.CNF
context = {
'form': form,
'reference_id': reference_id,
'manifests' : manifests,
'total_cases': total_cases,
'totalCNF': totalCNF,
}
return render(request, 'add_manifest.html', context)
add_manifest.html
<label for="form.reference" class="formlabels">Case Total:</label><br>
<input type="text" value="{{ total_cases }}" readonly>
I just want the number, not the whole reference to display in this HTML input box
The aggregate values are stored in dictionaries. You can use
{{ total_cases.cases__sum }}
to show the value only, or do it while constructing your context variable:
...
'total_cases': total_cases['cases__sum'],
I'm new in python/django and i have a problem, i'm trying to use checkbox filtering in my html table and i don't really know how to do it.
This is what i have now
I want to add these
models.py
class Tags(models.Model):
tag_frequency = models.CharField(max_length=250)
views.py
#login_required(login_url='/login/')
def index(request):
title = 'Tags'
all_tags = Tags.objects.all()
return render(request, 'tag/index.html' ,{'all_tags':all_tags, 'title':title})
How do i use filter with these, i tried something like this but doesn't work:
LF = 125 - 134.2 KHz
HF = 13.56 MHz
UHF = 860 - 960 MHz
LF = Tags.objects.filter(tag_frequency__gt=125, tag_frequency__lt=134.2)
In order to make your query works, you have to change your field to FloatField:
class Tags(models.Model):
tag_frequency = models.FloatField(default=0.00, null=True, blank=True)
Set null, blank and default values based on your needs.
Then, put your checkboxes (or radio inputs) in your html form like this:
<form action="" method="post">
<!-- other form fields and csrf_token here -->
<div><label for="input_lf"><input type="checkbox" name="is_lf" id="input_lf"> LF</label></div>
<div><label for="input_hf"><input type="checkbox" name="is_hf" id="input_hf"> HF</label></div>
<div><label for="input_uhf"><input type="checkbox" name="is_uhf" id="input_uhf"> UHF</label></div>
<input type="submit" value="Submit"/>
</form>
Then in your view, you can try something like this:
def form_view(request):
if request.method == 'POST':
# these strings come from HTML Elements' name attributes
is_lf = request.POST.get('is_lf', None)
is_hf = request.POST.get('is_hf', None)
is_uhf = request.POST.get('is_uhf', None)
# Now make your queries according to the request data
if is_lf:
LF = Tags.objects.filter(tag_frequency__gt=125, tag_frequency__lt=134.2)
if is_hf:
# another query here
# and rest of your view
I'm using using Django forms to collect information from users. But when I change between pages I want to use one of the value from url to be displayed in a from in the next page.
Example.
I have url for checking out a book like
http://127.0.0.1:8000/checkout/780374157067
780374157067 is the ibn of the book
Next page has a form where I get the ISBN and card id of the user. How to fill the form with the ISBN and show the form to user. rather than the user giving the ISBN again.
ISBN Filed should be pre filled with thw isbn in URL.
HTML :
<div class ="col-md-3">
<form method='POST' action=''>{%csrf_token%}
{{template_form | crispy}}
<input class="btn btn-lg btn-primary" type='submit'
value='Submit'/>
</form>
</div>
Forms.py
class loansform(forms.Form):
Isbn = forms.IntegerField()
Card_id = forms.IntegerField()
def clean_Isbn(self):
isbn = self.cleaned_data.get("Isbn")
isbn_string = str(isbn)
if len(isbn_string) != 13:
raise forms.ValidationError("Enter a valid ISBN-13")
return isbn
views.py
template_form = loansform();
in your view you can put intial data in form first get paramter from url then :
data = {'isbn': 154646486,}
form = Myform(initial=data)
in urls.py:
url(r'^checkout/(?P<isbn>\d+)/$',check_page)
view example :
def check_page(request, isbn):
data = {'isbn': isbn,}
form = Myform(initial=data)
template = 'mytem.html'
context = {'form': form,}
return render(request, template, context)
Say you've got url like
url(r'^checkout/(?P<isbn>\d+)/$')
In your view, when you instantiate form class, provide initial data to it like this.
form = YourFormClass(initial={'isbn': kwargs['isbn']})
kwargs contain url parameters, so you can get isbn from url.
I don't know how to check if user fill field in form in flask.
I have this form
<form method="POST" class="form-horizontal">
<input type="text" name="name" value="{{ name }}">
<input type="submit" class="btn" value="Add"/>
</form>
then I want check value in field and process it.
if request.method == 'POST':
name = request.form['name']
if name is None: // this doesn't work
# do something
if name == string.empty: // this also doesn't work
# do something
Please could you give me some advise.
Thanks
I see you could have two problems here, the first one is that you not specify an action attribute in your form, so first fill it with the url that will handle your form, the second
is that you are checking for None when an unfilled field is an empty string so you can use:
name = request.form['name']
if name == '':
# do something
Alternatively if you want to fill the field with a default value when it not exists you can use get dict method as:
name = request.form.get('name', None)
if name is None:
# do something
As other alternative you can use:
if not name:
# do something
cause '' evaluate to False in a boolean expression.
Try this:
if request.method == "POST":
ID = request.form['ID']
if not ID=="":
#do stuff`