I have two views one that accepts inputs and the other for confirmation and execution of an action. My problem is how to confirm the inputs from another view and template.
This is similar when you delete a record. That you should confirm from the user his actions.
Here is the input view. PreprocessinputationView:
def PreprocessInputationView(request, **kwargs):
proj_pk = kwargs.get('pk')
project = Project.objects.get(id=proj_pk)
df = pd.read_csv(project.base_file)
n_cols = df.keys
context = {}
context['df'] = df
context['n_cols'] = n_cols
context['project'] = project
if request.method == 'POST':
# try:
checked_value = request.POST.getlist(u'predictors')
method = ''.join(request.POST.getlist(u'method'))
if checked_value and method:
context['checked_value'] = checked_value
context['method'] = method
return render(request, 'projects/preprocess/confirm_inputation.html', context)
return render(request, 'projects/preprocess/preprocess_inputation.html', context)
The confirmation view goes here. ConfirmInputationView:
def ConfirmInputationView(request, context):
print('method:', context['method'])
project = context['project']
df = pd.read_csv(project.base_file)
n_cols = df.keys
filename = project.base_file.name
tmp = filename.split('/')
filename = str(tmp[1:])
if request.method == 'POST':
# try:
checked_value = context['checked_value']
method = context['method']
if checked_value and (method=='mean'):
df[checked_value].fillna(df[checked_value].mean())
# df.drop(columns=checked_values, inplace=True)
new_df = df.to_csv(index=False)
updated_file = ContentFile(new_df)
updated_file.name = filename
project.base_file = updated_file
project.save()
str_checked_value = ', '.join(checked_value)
context['str_checked_value'] = str_checked_value
if str_checked_value:
messages.success(request, f'Inputation to column(s) {str_checked_value} successful!')
return render(request, 'projects/preprocess/preprocess_inputation.html', context)
The confirmation template. Confirm_inputation.html:
{% extends "base.html" %}
{% block page_heading %}
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Delete Project</h1>
</div>
{% endblock page_heading %}
{% block content %}
<div class="jumbotron col-xl-8 col-md-6 mb-1"">
<form method=" POST">
{% csrf_token %}
<fieldset class='form-group'>
<p>
You have chosen <strong>{{ method }}</strong> as an inputation method?
Are you sure you want to proceed?
</p>
</fieldset>
<div class="form-group">
<button class="btn btn-danger float-sm-right mr-1" type="submit">Yes, Delete</button>
<a class="btn btn-secondary float-sm-right mr-1" href="{% url 'project-detail' project.id %}">Cancel</a>
</div>
</form>
</div>
{% endblock content %}
The data from the PreprocessImputationView should be passed to ConfirmImputationView for confirmation and processing.
I'm not sure I understand your question or rather problem. So I'll summarize what I understood. Please clarify more, if this doesn't fit your problem.
You have view A (PreprocessInputationView), which shows the user some values/forms and allows some POST action to A.
If view A receives a POST request you check the form input and render template B of view B.
Your rendered template B offers two options to the user: Accept, which triggers POST to view B or decline, which links to some details view.
I think what you're missing is, that context in render is "lost" after rendering. The moment the user sees the finished html page that variable is no longer relevant and inaccessible.
A way to provide the necessary 'method' information to your B view would be to add a form field to your B template, which holds some sort of key for B view to determine on POST what to do. Like a hidden input field with a number. Each number would predetermined stand for a method.
Related
I am trying to redirect the user to the previous page after they have updated an instance in the Model Class. So, here is the view for the update:
class ClassStatusDetailView(OrganisorAndLoginRequiredMixin, generic.UpdateView):
model = Class
template_name = "agents/class_status_detail.html"
context_object_name = "class"
fields = ['status']
def get_success_url(self):
return reverse("agents:agent-list")
Right now, as you can see, the get_success_url is set to "agents:agent-list", which is not the previous page. Also, here is the template for the update view in case you need it:
{% extends "base.html" %}
{% load tailwind_filters %}
{% block content %}
<div class="max-w-lg mx-auto">
<a class="hover:text-blue-500" href="#">Something</a>
<div class="py-5 border-t border-gray-200">
<h1 class="text-4xl text-gray-800">{{ class.student }}</h1>
</div>
<form method="post" class="mt-5">
{% csrf_token %}
{{ form|crispy }}
<button type='submit' class="w-full text-white bg-blue-500 hover:bg-blue-600 px-3 py-2 rounded-md">
Update
</button>
</form>
</div>
{% endblock content %}
However, there is a catch. The previous page I want to return to is a function view with a primary key. So, not only do I have to go back to this function view, but I also have to go to the correct primary key. Please tell me if you guys need any other information. Thank you!
When user successfully update their data then he/she redirect to class_list.html page..
urls.py(I assume):
path('class_list/<int:pk>/', class_list,name = 'class_list'),
path('edit_class/<int:pk>/', ClassStatusDetailView.as_view(),name = 'edit_class')
models.py:
class ClassStatusDetailView(OrganisorAndLoginRequiredMixin, generic.UpdateView):
model = Class
template_name = "agents/class_status_detail.html"
context_object_name = "class"
fields = ['status']
def get_success_url(self):
agent_id = self.object.teacher.id
return reverse_lazy('class_list', kwargs={'pk': agent_id})
Use reverse_lazy
My flask form is not getting validated.
#admin_blueprints.route('/ManageMovies',methods=['GET', 'POST'])
def ManageMovie():
form = SetShowForm(request.form)
if request.method == 'POST' and form.validate():
print(form.movie.data)
return redirect(url_for('admin.AdminHome'))
engine = create_engine('mssql+pyodbc://DESKTOP-6UNRAN0/movie_f?driver=SQL Server?
Trusted_Connection=yes')
form.movie.choices = [(movie.m_id, movie.m_name)for movie in (engine.execute('select * from
MovieMaster'))]
form.show_time.choices = [(time.s_id, time.s_time) for time in (engine.execute('select * from
ShowTime'))]
return render_template('manage_movies.html',form=form)
my template code is
{% extends "master.html" %}
{% block content %}
<form method="POST">
{{ form.hidden_tag() }}
{{form.movie.label}}{{form.movie(class="form-control")}}
<br>
{{ form.show_time.label }} {{form.show_time(class="form-control")}}
<br>
{{form.price.label}} {{ form.price(class="form-control") }}
<br>
{{form.submit(class="btn btn-success")}}
</form>
{% endblock %}
my flask form
class SetShowForm(FlaskForm):
movie = SelectField('Movie Name', choices=[])
show_time = SelectField('Set Show Time',choices=[])
price = IntegerField('Price')
submit = SubmitField("Set")
Once I click on my submit button, the same page gets rendered again instead of entering my (if request.method == 'POST' and form.validate():) statement and printing the data. I have no idea what is going wrong. I am filling all the fields. Are there any rule for form validation.
I believe you need to use:
if form.validate_on_submit():
And you don't need to check for "POST" because validate_on_submit does that too.
Try it
#admin_blueprints.route('/ManageMovies',methods=['GET', 'POST'])
def ManageMovie():
form = SetShowForm()
if form.validate_on_submit():
print(form.movie.data)
return redirect(url_for('admin.AdminHome'))
return render_template('manage_movies.html',form=form)
And set choices values in setShowForm() directly
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>
[** found a fix, see below **]
I'm having trouble getting Django 2 Paginator to work with a modelformset. There are three models, Place & Hit (one-to-many), and Link. The 'validator' view pages through Place objects 1 at a time, builds a queryset of Hits filtered by the FK placeid. The context sent to the template includes 1) the formset=HitFormSet, 2) a 'records' list with only the one Place object, and 3) the Paginator page.
The template renders the single Place record on the left side, and a scrolling list of Hit forms on the right. The Hit form has two added fields, 'match' (3 radio buttons) and 'flag' (checkbox). The user selects those if one or more Hits match the Place. Upon submitting, a new Link record is created with a placeid, a hitid, and values from the radios and checkbox. Also, a 'reviewed' field in the Place record is set to True.
The code below works to load Place #1, then page through the records - displaying a Place and its Hits. Clicking the Save button creates a new Link record as desired. The problem is that after the save, although the next Page loads on the left, its corresponding hits don't. By displaying pprint(locals()) I can see the correct hits are in the queryset, but the Hit fields in the formset all retain the values from the previous set of forms. The Paginator is advancing and the next Place loads, but not its Hit formset.
I've banged at this for a couple days, read docs, searched, etc. Any ideas?
view.py
def validator(request):
record_list = Place.objects.order_by('placeid').filter(reviewed=False)
paginator = Paginator(record_list, 1)
page = request.GET.get('page')
records = paginator.get_page(page)
count = len(record_list)
context = {
'records': records,
'page': page if request.method == 'GET' else str(int(page)-1)
}
placeid = records[0].placeid
hitid = records[0].hitid
q = Hit.objects.filter(placeid=placeid)
HitFormset = modelformset_factory(
Hit, fields = ['id','hitid', ],form=HitModelForm,extra=0)
formset = HitFormset(request.POST or None, queryset=q)
context['formset'] = formset
if request.method == 'GET':
method = request.method
print('a GET')
else:
if formset.is_valid():
print('formset is valid')
for x in range(len(formset)):
link = Link.objects.create(
placeid = placeid,
hitid = formset[x].cleaned_data['hitid'],
match = formset[x].cleaned_data['match'],
flag = formset[x].cleaned_data['flag'],
)
# flag Place record as reviewed
matchee = get_object_or_404(Place, placeid = placeid)
matchee.reviewed = True
matchee.save()
else:
print('formset is NOT valid')
print(formset.errors)
pprint(locals())
return render(request, 'validator/template.html', context=context)
template.html
{% block content %}
<div class="pagination">
<span class="step-links">
... all standard, works fine
</span>
</div>
{% for record in records %}
{% if records.has_next %}
<!-- <form id="form_related" method="POST" action="" > -->
<form id="form_related" method="POST" action="?page={{ records.next_page_number }}" >
{% else %}
<form id="form_related" method="POST" action="" >
{% endif %}
{% csrf_token %}
{{ formset.management_form }}
<input type="hidden" name="placeid" value="{{ record.placeid }}" />
{% for form in formset %}
<div class="row">
<div class="col-sm-4 id="place-record">
<!-- Place attributes -->
</div>
<div class="col-sm-8" id="hit-forms">
<div id="review">
<span>{{ form.match }} flag: {{ form.flag_geom }}</span>
</div>
<div id="hit">
<!-- Hit attributes -->
</div>
</div>
</div>
{% endfor %}
{% endfor %}
{% endblock%}
The answer (or an answer) turned out to be doing a redirect immediately after the save/POST. The save of Link record removes the Place from the queue, so the page is always "1"
view.py
...
if formset.is_valid():
for x in range(len(formset)):
link = Link.objects.create(
placeid = placeid,
tgnid = formset[x].cleaned_data['tgnid'],
match = formset[x].cleaned_data['match'],
flag_geom = formset[x].cleaned_data['flag_geom'],
)
matchee = get_object_or_404(Place, placeid = placeid)
matchee.reviewed = True
matchee.save()
return redirect('/formset/?page='+page)
else:
print('formset is NOT valid')
print(formset.errors)
...
I have a model with a lot of fields. I only have a few fields I that I want to be required. So instead of the change list super long, I want to have a short change list then have admin actions that can give predefined subsets of the fields.
The initial action takes me to the correct page but when I submit the form it returns me to whatever page I designate, but doesn't update the fields. I am okay with tearing this down starting over again if needed. I think what I really need to know, what do I put in the action="" portion of the html to have the recursion work properly?
I am using django 1.7. I have to obfuscate a lot of my fields as a cya thing since I am working in a heavily information secure field.
Here is my admin.py
class CredentialAdmin(admin.ModelAdmin):
fields = ['reservedBy','reserveto']
list_display = ['reservedBy','reserveto']
class reserveToFormAdmin(forms.Form):
reservedBy = forms.CharField(widget=forms.Textarea, max_length=50)
reserveto = forms.DateTimeField(widget=forms.DateTimeInput)
def reserveCred(self, request, queryset):
form = None
plural = ''
if 'submit' in request.POST:
form = self.reserveToFormAdmin(request.POST)
for f in form.fields:
print f
print form.is_valid()
print form.errors
if form.is_valid():
reservetos = form.cleaned_data['reserveto']
reservedBys = form.cleaned_data['reservedBy']
print "hello"
count = 0
for cred in queryset:
cred.reserveto = reservetos
cred.reservedBy = reservedByss
cred.save()
count += 1
if count != 1:
plural = 's'
self.message_user(request, "Successfully reserved %s cred%s." % (count, plural))
return HttpResponseRedirect(request.get_full_path(),c)
if not form:
form = self.reserveToFormAdmin(initial={'_selected_action' : request.POST.getlist(admin.ACTION_CHECKBOX_NAME)})
return render(request,'admin/reserveCreds.html',{'creds':queryset, 'form':form, 'path':request.get_full_path()})
reserveCred.short_description = "Reserve Selected Creds"
actions = [check_out_a_cred,check_in_a_cred,audit_creds,CompareAudits,reserveCred]
reserveCreds.html
{% extends "admin/base_site.html" %}
{% block content %}
<p>How long and which department to reserver creds:</p>
<form action="{{ path }}" method="post">{% csrf_token %}
{{ form }}
<input type="submit" name="submit" value="submit" />
<input type="button" value = "Cancel" />
</form>
<h2> reserving: </h2>
<ul>
{% for cred in creds %}
<li> {{ cred.userid }} </li>
{% endfor %}
</ul>
{% endblock %}