Django: How save partial filled form state - django

I don't know exactly how to ask this question.
The thing is that I have a main view to create new entries in a model. This model has some 1-many relations, so I added a + button to add new entries of this fields (secondary model) in case they did not exist. When I submit this new data I redirect to the previous page (main view), and if you already filled some fields in the main view, that information is lost.
Can someone suggest me what the best way to deal with this would be?
Thanks in advance!
UPDATE:
'main model view'
class OrganismCreate(LoginRequiredMixin,CreateView):
"""Template: //catalog/templates/catalog/organism_form.html"""
model = Organism
fields = '__all__'
'main model template' (part)
<form action="" method="post">
{% csrf_token %}
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">Add a new entry: </div>
<div class="panel-body">
<hr>
<div class="row">
<div class="form-group col-sm-4 col-md-3">
<div class="form-group col-sm-4 col-md-3">
<label for="id_inst_own">Owner:</label>
{% render_field form.inst_own class="form-control" %}
<i class="fa fa-plus-circle "></i> Add new
</div>
<div class="panel panel-default">
<div class="panel-body">
...........................................
<button type="submit" class="btn btn-primary"> <span class="glyphicon glyphicon-filter"></span> submit </button>
</div>
</div>
</div>
Then the related model view:
def test_f(request):
if request.method == "GET":
Form = InstitutionForm()
render(request, 'catalog/institution_form.html')
if request.method == "POST":
Form = InstitutionForm(request.POST)
if Form.is_valid():
Form.save()
next = request.POST.get('next', '/')
return redirect(next)
pre=request.META.get('HTTP_REFERER')
return render(request, 'catalog/institution_form.html',{"form" : Form, "pre": pre})
And the related model template
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="hidden" name="next" value="{{ pre }}">
<input type="submit" class="btn btn-success" value="Submit" />
</form>
{% endblock %}

There are a number of ways to solve this problem. Here's some suggestions. Not an exclusive list:
Save the incomplete model data in the database as as a 'draft' version of the final data. This could be a totally different model or else using the same model (assuming the related fields are nullable) and giving it a 'draft' flag or similar.
Use an inline formset to create the related objects in the same view. Django Extra Views has some useful tools for this (https://github.com/AndrewIngram/django-extra-views).
Using JavaScript, save the unfinished form data to local storage and then recover it when the original form is loaded again.

I have implemented a draft system to do this along the lines of 1. in #ChidG's answer.
In models I have something like
class AbstractThing(models.Model):
field = models.CharField()
class Meta:
abstract = True
class CompleteThing(AbstractThing):
class Meta:
managed = True
db_table = 'complete_thing'
class IncompleteThing(AbstractThing):
fields_to_not_blank = [AbstractThing._meta.get_field(x) for x in []] #if you don't want to change some fields
for f in AbstractThing._meta.fields:
if f not in fields_to_not_blank:
f.blank = True
f.null = True
class Meta:
managed = True
db_table = 'incomplete_thing'
Then you can use model forms and handle the cases in your views.

Related

The right way to dynamically add Django formset instances and POST usign HTMX?

I'm making a form with a nested dynamic formset using htmx i (want to evade usign JS, but if there's no choice...) to instance more formset fields in order to make a dynamic nested form, however when i POST, only the data from 1 instance of the Chlid formset (the last one) is POSTed, the rest of the form POSTs correctly and the Child model gets the relation to the Parent model
I read the django documentation on how to POST formset instances and tried to apply it to my code, also i got right how to POST both Parent and Child at the same time. For the formsets i'm making a htmx get request hx-get to a partial template that contains the child formset and that works great, the only problem is that this always returns a form-0 formset to the client side, so for the POST the data repeats x times per field and only takes the data placed in the last instance, however i tried to change the extra=int value on my formset to get more forms upright, this gave the expected result, one Child instance per form in extra=int, so my problem is up with htmx and the way i'm calling the new Child formset instances.
here's my code. (i plan to nest more child formsets inside this form so i call this sformset for conveniece)
****views.py****
def createPlan(request):#Requst for the Parent form
form = PlanForm(request.POST or None)
sformset = StructureFormset(request.POST or None) #Nesting the Child formset
context = {
'form':form,
'sformset':sformset,
}
if request.method == 'POST':
print(request.POST)
if form.is_valid() and sformset.is_valid():
plan = form.save(commit=False)
print(plan)
plan.save()
sform = sformset.save(commit=False)
for structure in sform:
structure.plan = plan
structure.save()
return render(request, 'app/plan_forms.html', context)
def addStructure(request):
sformset = StructureFormset(queryset=Structure.objects.none())#add a empty formset instance
context = {"sformset":sformset}
return render(request, 'app/formsets/structure_form.html', context)
****forms.py****
StructureFormset = modelformset_factory(Structure,
fields = (
'material_type',
'weight',
'thickness',
'provider'
))
****relevant part for plan_forms.html template****
<form method="POST">
{% csrf_token %}
<div class="col-12 px-2">
<div class="row px-3 py-1">
<div class="col-3 px-1">{{ form.format }}</div>
<div class="col-3 px-1">{{ form.pc }}</div>
<div class="col-3 px-1">{{ form.revission }}</div>
<div class="col-3 px-1">{{ form.rev_date }}</div>
</div>
<div class="row px-3 py-1">
<div class="col-3 px-1">{{ form.client }}</div>
<div class="col-3 px-1">{{ form.product }}</div>
<div class="col-3 px-1">{{ form.gp_code }}</div>
<div class="col-3 px-1">{{ form.code }}</div>
</div>
</div>
<div>
<table>
<tbody style="user-select: none;" id="structureforms" hx-sync="closest form:queue">
<!--Structure formset goes here-->
</tbody>
<tfoot>
<a href="" hx-get="{% url 'structure-form' %}" hx-swap="beforeend" hx-target="#structureforms">
Add structure <!--Button to call structure formset-->
</a>
</tfoot>
</table>
</div>
<div class="col-12 px-2">
<div class="row px-4 py-1">{{ form.observation }}</div>
<div class="row px-4 py-1">{{ form.continuation }}</div>
<div class="row px-4 py-1">{{ form.dispatch_conditions }}</div>
<div class="row px-3 py-1">
<div class="col-6 px-1">{{ form.elaborator }}</div>
<div class="col-6 px-1">{{ form.reviewer }}</div>
</div>
</div>
<button type="submit">Submit</button>
</form>
****formsets/structure_form.html****
<tr>
<td class="col-12 px-1">
{{ sformset }}
</td>
</tr>
**** relevant urls.py****
urlpatterns = [
path('create_plan/', views.createPlan, name='create_plan'),
path('htmx/structure-form/', views.addStructure, name='structure-form')]
Additionally, the form that i built in admin.py using fields and inlines is just exactly what i want as the raw product (except for the amount of initial formsets and styles)
To summarize the problem: At present, your code successfully brings in the new formset, but each new formset comes with a name attribute of form-0-title (ditto for id and other attributes). In addition, after adding the new formset with hx-get the hidden fields originally created by the ManagementForm will no longer reflect the number of formsets on the page.
What's needed
After a new formset is added to the site, here's what I think needs to happen so Django can process the form submission.
Update the value attribute in the input element with id="id_form-TOTAL_FORMS" so the number matches the actual number of formsets on the page after hx-get brings in the new formset.
Update the name and id of the new formset from form-0-title to use whatever number reflects the current total number of formsets.
Update the labels' for attributes in the same way.
You can do this with Javascript on the client side. Alternatively, you can do effectively the same thing with Django on the server side and then htmx can be the only javascript needed to do the rest. For that, I have used empty_form to create the html content of a formset which can be altered as needed. That work is shown in the build_new_formset() helper, below.
Example
Here's what I have working:
forms.py
from django import forms
from django.forms import formset_factory
class BookForm(forms.Form):
title = forms.CharField()
author = forms.CharField()
BookFormSet = formset_factory(BookForm)
views.py
from django.utils.safestring import mark_safe
from app2.forms import BookFormSet
def formset_view(request):
template = 'formset.html'
if request.POST:
formset = BookFormSet(request.POST)
if formset.is_valid():
print(f">>>> form is valid. Request.post is {request.POST}")
return HttpResponseRedirect(reverse('app2:formset_view'))
else:
formset = BookFormSet()
return render(request, template, {'formset': formset})
def add_formset(request, current_total_formsets):
new_formset = build_new_formset(BookFormSet(), current_total_formsets)
context = {
'new_formset': new_formset,
'new_total_formsets': current_total_formsets + 1,
}
return render(request, 'formset_partial.html', context)
# Helper to build the needed formset
def build_new_formset(formset, new_total_formsets):
html = ""
for form in formset.empty_form:
html += form.label_tag().replace('__prefix__', str(new_total_formsets))
html += str(form).replace('__prefix__', str(new_total_formsets))
return mark_safe(html)
Note re: build_new_formset() helper: formset.empty_form will omit the index numbers that should go on the id, name and label attributes, and will instead use "__prefix__". You want to replace that "__prefix__" part with the appropriate number. For example, if it's the second formset on the page its id should be id_form-1-title (changed from id_form-__prefix__-title).
formset.html
<form action="{% url 'app2:formset_view' %}" method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<p>{{ form }}</p>
{% endfor %}
<button type="button"
hx-trigger="click"
hx-get="{% url 'app2:add_formset' formset.total_form_count %}"
hx-swap="outerHTML">
Add formset
</button>
<input type="submit" value="Submit">
</form>
formset_partial.html
<input hx-swap-oob="true"
type="hidden"
name="form-TOTAL_FORMS"
value="{{ new_total_formsets }}"
id="id_form-TOTAL_FORMS">
<p>{{ new_formset }}</p>
<button type="button"
hx-trigger="click"
hx-get="{% url 'app2:add_formset' new_total_formsets %}"
hx-swap="outerHTML">
Add formset
</button>
Note re: the hidden input: With every newly added formset, the value of the input element that has id="id_form-TOTAL_FORMS" will no longer reflect the actual number of formsets on the page. You can send a new hidden input with your formset and include hx-swap-oob="true" on it. Htmx will then replace the old one with the new one.
Docs reference: https://docs.djangoproject.com/en/4.1/topics/forms/formsets/

add multiple forms to page on button click

I am working on developing a permitting app using django. This is my first django project so bear with me here...
we have a default utility permit that contains some basic info like property owner and address. Then from that you can attach a sewer, or water or row or any combination of related tables to the permit. Basically I am looking for a way to return a page with the default utility permit then have a series of links or buttons to add more forms to that page.
I made some model forms for each of the models and can display them individually on the page
forms.py
class UtilityPermitForm(forms.ModelForm):
class Meta:
model = UtilityPermit
fields = ['...']
class SewerPermitForm(forms.ModelForm):
class Meta:
model = SewerPermit
fields = ['...']
class WaterPermitForm(forms.ModelForm):
class Meta:
model = WaterPermit
fields = ['...']
I successfully added them to a list and could iterate through and get them to add
views.py
class BuildForms(View):
permits = []
utility_form = UtilityPermitForm
sewer_form = SewerPermitForm
water_form = WaterPermitForm
permits.append(utility_form)
permits.append(sewer_form)
permits.append(water_form)
template_name = 'engineering/UtilityPermitForm2.html'
def get(self, request, *args, **kwargs):
out_permits = []
for form in self.permits:
out_permits.append(form())
return render(request, self.template_name, {'form': out_permits})
def post(self, request, *args, **kwargs):
if request.GET.get('testButton'):
return HttpResponse("I guess")
form = self.utility_form(request.POST)
return render(request, self.template_name, {'form': form})
def add_permit(self, request, permit):
# need to get a thing to add a permit to the list
pass
.html
{% block content %}
<div>
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{% for item in form %}
{{ item }}
<hr>
{% endfor %}
<input type="submit" value="Submit">
</form>
</div>
{% endblock content %}
so again, my problem is I want to start with a one permit and then have links or buttons to add each form as needed. I'm a bit at a loss here and any help would be greatly appreciated.
EDIT:
so I have this base permit that comes up when a user navigates to it like so, and I want to have a user click the add sewer permit button or link or whatever
and then the corresponding permit will come up
you can create multiple same form in one page dynamically using formset
see Documentation
and maybe this tutorial is exactly what you are looking for.
EDITED
if I understand your question correctly, how about this:
first, it would be better to separate your form with dictionaries instead of list in your views.py
context = {
'utility_form': self.utility_form,
'sewer_form': self.sewer_form,
'water_form': self.water_form
}
return render(request, self.template_name, context)
then in your .html file,
if you want to add one form each time you click the button, my trick is:
show your base permit form first (said utility_form), button to add other form, and hide your other form first.
<div class="form-container">
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{{ utility_form }}
<div id="additional-forms"></div> <!-- notice this div -->
<hr>
<input type="submit" value="Submit">
</form>
</div>
<button class="add-sewer-form">Sewer Permit</button>
<div id="sewer-form-template" style="display: none;">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
and then using jquery to add onclick listener, clone that hidden form, then insert it after base form (actually inside div with id additional-forms).
$('.add-sewer-form').click(function(){
let sewer_form = $('#sewer-form-template .sewer-form-container:first').clone(true);
$(sewer_form).appendTo($('#additional-forms'))
});
I haven't test it yet, but when you click the add button, it should be give result like this:
<div class="form-container">
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{{ utility_form }}
<div id="additional-forms">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
<hr>
<input type="submit" value="Submit">
</form>
</div>
<button class="add-sewer-form">Sewer Permit</button>
<div id="sewer-form-template" style="display: none;">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
Hope it can answer your question :)
First add the button
<button><button>
Then add onclick attribute to it which will help react on click
<button onclick='do'><button>
Then create script that contain the function to display the other form
<script>
function do() {
document.getElementById('form').innerHTML ='add your form here'
}
</script>
all together
<button onclick='do'><button>
<script>
function do() {
document.getElementById('form').innerHTML ='add your form here'
}
</script>

Django Crispy Forms - Checkbox not being displayed

I'm trying to add a boolean field on my form and render it with crispy forms tags. And everything is showed except for the checkbox.
My project works with django 2.1, python 3.6 and Bootstrap-4. My version of Django Crispy Forms is: 1.7.2
The field is investment.
Model field not working:
investment = models.BooleanField(default=False, help_text='Want to accept Investments?')
My form:
class CreateProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ('name', 'short_description', 'category', 'investment')
widgets = {
'name': forms.TextInput(attrs={'placeholder': 'enter the project name here...'}),
'short_description': forms.Textarea(attrs={'rows': '2', 'maxlength': '135', 'class': 'textarea-limited',
'placeholder': 'enter a short description of your project limited to 135 characters'}),
}
def __init__(self, *args, **kwargs):
# first call parent's constructor
super(CreateProjectForm, self).__init__(*args, **kwargs)
# there's a `fields` property now
self.fields['investment'].required = True
self.fields['investment'].widget = forms.CheckboxInput()
self.fields['name'].widget = forms.TextInput(
attrs={'placeholder': 'enter the project name here...'})
self.fields['short_description'].widget = forms.Textarea(
attrs={'rows': '2',
'maxlength': '135',
'class': 'textarea-limited',
'placeholder': 'enter a short description of your project limited to 135 characters'})
# evade all labels and help text to appear when using "as_crispy_tag"
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper._help_text_inline = True
My View:
class ProjectCreateView(SuccessMessageMixin, generic.CreateView):
template_name = 'webplatform/project_create_form.html'
model = Project
form_class = CreateProjectForm
success_message = 'Project created! Now try to add all the details and then publish it!'
def get_success_url(self):
return reverse_lazy('project-edit-general', args=(self.object.id,))
# Set field as current user
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.start_date = timezone.now()
form.instance.history_change_reason = 'Project Created'
return super(ProjectCreateView, self).form_valid(form)
And for the template I tried two methods, but none of them worked:
My template 01:
This is the method I want to use at the end. Displaying each fiend individually so I can make the layout directly on the template.
...
{% load crispy_forms_tags %}
...
<form id="my_form" method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
<div class="row">
<div class="col-md-5 col-sm-5">
<h6>Name
<span class="icon-danger">*</span>
</h6>
{{ form.name|as_crispy_field }}
<h6>Categories
<span class="icon-danger">*</span>
</h6>
{{ form.category|as_crispy_field }}
</div>
<div class="col-md-7 col-sm-7">
<h6>Short Description
<span class="icon-danger">*</span>
</h6>
{{ form.short_description|as_crispy_field }}
<h5>
<small>
<span id="textarea-limited-message" class="pull-right">135 characters left</span>
</small>
</h5>
<h6>Investment
<span class="icon-danger">*</span>
</h6>
{{ form.investment|as_crispy_field }}
</div>
</div>
<div class="row buttons-row">
<div class="col-md-4 col-sm-4">
<button type="submit" class="btn btn-outline-primary btn-block btn-round">Create</button>
</div>
</div>
</form>
My template 02:
This one is using directly the {{ form|crispy }} to show all the elements automatically.
...
{% load crispy_forms_tags %}
...
<form id="my_form" method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{{ form|crispy }}
<div class="row buttons-row">
<div class="col-md-4 col-sm-4">
<button type="submit" class="btn btn-outline-primary btn-block btn-round">Create</button>
</div>
</div>
</form>
I checked the rendered HTML and I found where the problem seems to be, but I don't know how to solve it:
Crispy forms create an element adding the corresponding divs and other necessary elements, like for example on the name input:
<div id="div_id_name" class="form-group">
<label for="id_name" class="col-form-label requiredField">Name
<span class="asteriskField">*</span>
</label>
<div class="">
<input type="text" name="name" placeholder="enter the project name here..." class="textinput textInput form-control" required="" id="id_name">
<small id="hint_id_name" class="form-text text-muted">Add a title to your project.</small>
</div>
</div>
But for the checkbox creates the following structure:
<div class="form-group">
<div id="div_id_investment" class="form-check">
<label for="id_investment" class="form-check-label requiredField">
<input type="checkbox" name="investment" class="checkboxinput form-check-input" required="" id="id_investment">
Investment
<span class="asteriskField">*</span>
</label>
<small id="hint_id_investment" class="form-text text-muted">Want to accept Investments?</small>
</div>
</div>
As you can see, the div with the id is inside another div. Well, so if I delete the class of this extra div (form-group) and change the class of the div with id: form-check for form-group, the checkbox appears and is fully functional.
So my idea is try to change the template that crispy forms created for the checkbox, But I don't know how to do that. Also, if there is another better option, I'm open to them.
Try to change self.fields['investment'].required = False, 'cause it seems that because the field is not specified as optional Django ignores it.
Their is an open issue in django-crispy-forms github see : https://github.com/django-crispy-forms/django-crispy-forms/issues/787
According to this the issue is the way bootsrap handle this form element in the last version.
Here is a js hack to make it work :
$(document).ready(function() {
$( ":checkbox" ).each(function( index ) {
$(this).prependTo($("#div_" + $(this).attr('id')))
});
});
I could make a half hack for this by the element I needed by using the following JS:
$(window).on('load',function(){
$('#div_id_investment').addClass('form-group').removeClass('form-check');
});
But this just let the user see and interact with the checkbox, it does not solve that if the field is required and you don't click it, the error message it doesn't appear.
If anyone have an improved JS to make this to all checkboxes and solve the problem with the error message, I'll appreciate it.
note: I'm not marking this as a valid answer for the question because the bug still there and this 'hack' doesn't solve all the problems.

Django - Taking of object model by select tag and passing this object to another view

I'm struggling with the following problem. In my project I have the following model:
models.py
class InputSignal(models.Model):
name = models.CharField(max_length=512)
author = models.ForeignKey(User, on_delete=models.CASCADE)
adnotations = models.TextField(blank=True, null=True)
input_file = models.FileField(upload_to='signals/', null=False, validators=[validate_file_extension])
add_date = models.DateTimeField(default=datetime.now())
last_edit_date = models.DateTimeField(default=datetime.now())
last_json_results = models.FileField(upload_to='resuts/')
objects = models.Manager()
def delete(self):
self.input_file.delete()
super().delete()
def __str__(self):
return self.name
def add_date_pretty(self):
return self.add_date.strftime('%b %e %Y')
Two url addresses:
urls.py
path('display/list', displayviews.display_list, name='display-list'),
path('display/details/<int:signal_id>', displayviews.display_details, name='display-details'),
And two view functions:
views.py
def display_list(request):
signals = InputSignal.objects.filter(author=request.user)
return render(request, 'display_list.html', {'signals': signals})
def display_details(request, signal_id):
signal = get_object_or_404(InputSignal, pk=signal_id)
The template of the first function of the view at this moment looks like this:
display_list.html
<div class="row mt-2">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<select class="form-control mt-2 text-center">
{% for signal in signals %}
<option>
<h2>{{ signal.name }}</h2>
</option>
{% endfor %}
</select>
</div>
<div class="col-lg-1"></div>
</div>
<div class="row mt-3 mb-2">
<div class="col-lg-4"></div>
<div class="col-lg-4">
Perform Analysis
</div>
<div class="col-lg-4"></div>
</div>
I would like based on the structure of this template to design a solution that after selecting the signal name from the select tag and clicking the 'perform analysis' button, go to the next view - display_details (request, signal_id). Where I will save the previously selected model object to the variable. Choosing the right object I would like to use the object ID. I would like to ask for help, what I was able to design presented above.
A couple of things here.
To submit data from a web page you need a form element (unless you're using Ajax, which doesn't seem necessary here). Your select box needs a name attribute, and each option needs a value to submit. Also, you can't submit a form with an a link; you need a submit button. So:
<form action="{% url 'display-details' %}">
<select name="signal_id" class="form-control mt-2 text-center">
{% for signal in signals %}
<option value="{{ signal.id }}">
<h2>{{ signal.name }}</h2>
</option>
{% endfor %}
<button class="btn btn-outline-success btn-block">Perform Analysis</button>
</form>
Now this data is being submitted in the querystring to your display_details view, eg "/display/details/?signal_id=5". So you need to remove the parameter from the URL pattern, and get the data inside the view from the GET params:
path('display/details/', displayviews.display_details, name='display-details'),
...
def display_details(request):
signal_id = request.GET['signal_id']
signal = get_object_or_404(InputSignal, pk=signal_id)

In django, how to use another model data from function based views

So I have a form that updates a key_instance object with a borrower. Currently my app needs the user to enter the name of the borrower, but I want it to display a dropdown list of data from another model the user model to select from, is there anyway to do this in a class based view? Here are my views.py and my template. What I was thinking is that I would like to use a get_list_or_404 on the user model and display it as a drop down list in the template and use that selection to populate the form field.
I manged to get the dropdown list to display in my template but I'm not sure as to how to save that value in my views.
Does anyone know if this is the right way or if this is doable? Thank you!!
views.py
def submit_key_request(request, pk):
"""
View function for renewing a specific keyInstance by admin
"""
key_inst=get_object_or_404(KeyInstance, pk=pk)
names = get_list_or_404(Users)
# If this is a POST request then process the Form data
if request.method == 'POST':
# Create a form instance and populate it with data from the request (binding):
form = UpdateKeyForm(request.POST)
# Check if the form is valid:
if form.is_valid():
# process the data in form.cleaned_data as required (here we just write it to the model due_back field)
key_inst.is_requested = True
key_inst.status = 'r'
key_inst.date_requested = datetime.date.today()
key_inst.borrower = form.cleaned_data['borrower']
key_inst.save()
# redirect to a new URL:
return HttpResponseRedirect(reverse('all-available-keys') )
# If this is a GET (or any other method) create the default form.
else:
form = UpdateKeyForm(initial={'borrower': 'N/A'})
return render(request, 'catalog/keyinstance_request_update.html', {'form': form, 'keyinst':key_inst})
template
{% extends "base_generic.html" %}
{% block content %}
<div class="wrapper">
<div class="centered"> <h1>Request Keys For Room: {{keyinst.roomkey}}</h1></div>
<div class="square-box">
<div class="square-content">
<form action="" method="post" >
{% csrf_token %}
<table style="display: inline-flex">
{{ form}}
</table>
<select name = 'name'>
{% for name in names %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
<p>
(Please use their login name i.e. <b>{{ user.get_username }}</b>)
</p>
<p><input required id="checkBox" type="checkbox" onclick="validate()"> I accept the terms and conditions</p>
<p id="text" style="display:none">You Have Agreed To the Terms and Conditions</p>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}
Here is how I manged to do it, Not sure if this is the best 'pythonic' or best practice. Please let me know if it's not.
my views.py
def submit_key_request(request, pk):
"""
View function for renewing a specific keyInstance by admin
"""
key_inst=get_object_or_404(KeyInstance, pk=pk)
names = get_list_or_404(User)
# If this is a POST request then process the Form data
if request.method == 'POST':
name = request.POST['name']
key_inst.is_requested = True
key_inst.status = 'r'
key_inst.date_requested = datetime.date.today()
key_inst.borrower = name
key_inst.save()
return HttpResponseRedirect(reverse('all-available-keys') )
# If this is a GET (or any other method) create the default form.
else:
pass
return render(request, 'catalog/keyinstance_request_update.html', {'keyinst':key_inst, 'names':names})
template
{% extends "base_generic.html" %}
{% block content %}
<div class="wrapper">
<div class="centered"> <h1>Request Keys For Room: {{keyinst.roomkey}}</h1></div>
<div class="square-box">
<div class="square-content">
<form action="" method="post" >
{% csrf_token %}
</br>
<select name = 'name' required>
{% for key in names %}
<option value="{{ key }}">{{ key }}</option>
{% endfor %}
</select>
<p>
(Please use their login name i.e. <b>{{ user.get_username }}</b>)
</p>
<p><input required id="checkBox" type="checkbox" onclick="validate()"> I accept the terms and conditions</p>
<p id="text" style="display:none">You Have Agreed To the Terms and Conditions</p>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}