Simple Django form and get value submitted - django

I would like to create a Django form very easy, than I would like to pick up the value from both fields.
This is my form :
class SettingsForm(forms.Form):
download_validity = forms.CharField(label='Expiry Download')
flag_validity = forms.CharField(label='Expiry Flag')
def __init__(self, *args, **kwargs):
super(SettingsForm, self).__init__(*args, **kwargs)
Then, I have a view :
class SettingsView(FormView):
template_name = 'settings.html'
form_class = SettingsForm
def get_context_data(self, **kwargs):
subtitle = _("Manage Settings")
context_data = super(SettingsView, self).get_context_data(**kwargs)
context_data['subtitle'] = subtitle
return context_data
def form_valid(self, form):
download_validity = form.cleaned_data['download_validity']
flag_validity = form.cleaned_data['flag_validity']
print(download_validity)
print(flag_validity)
return super(SettingsView, self).form_valid(form)
And finally my template view :
{% block main %}
<div class="container">
<div class="row">
<form autocomplete="off" method="get" action="">
<fieldset>
<legend class="title"><span class="name">{% trans 'Expiry Download link' %}</span></legend>
</fieldset>
{{ form.download_validity|as_crispy_field }}
<input type="submit" class="btn btn-default" name="UpdateDownload" value="{% trans 'Update' %}"/>
</form>
</div>
<div class="row">
<form autocomplete="off" method="get" action="">
<fieldset>
<legend class="title"><span class="name">{% trans 'Expiry New Publication' %}</span></legend>
</fieldset>
{{ form.flag_validity|as_crispy_field }}
<input type="submit" class="btn btn-default" name="UpdateFlag" value="{% trans 'Update' %}"/>
</form>
</div>
</div>
{% endblock main %}
I don't know why, but I would like to get value thanks to cleaned_data but the print function doesn't display anything. I don't know if I missed something but all seems to be right.
I have to create 2 forms in my forms.py file instead of one ?

In your template you should create the form outside of your rows, like so:
<form ...>
<div class="row">
<input .../>
</div>
<div class="row">
<input .../>
</div>
</form>
Have you made sure if your form is both valid and also being posted? (You could just simply debug inside your view and a few more prints that check if the request is POST etc. Maybe you are also missing your CSRF-Token as it isn't defined in your template (https://docs.djangoproject.com/en/2.1/ref/csrf/)
You could also let the form render itself. For example via {% crispy form %} in your case (https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html)

Related

passing instance to Django modal form

I want to do edit on a modal pop up form, edit is working but cant see the existing instance, how I can do it? any help is appreciated.
Here I have passed the form as below
class DomainListView(ListView):
model = Domain
template_name = 'super_admin/domain_list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = DomainEditForm(self.request.POST or None)
context['form'] = form
return context
and the template is as follows
<div class="modal fade" id="domain-edit-{{ item.pk }}">
<div class="modal-dialog" role="document">
<form class="form-valide" action="{% url 'domain_edit' item.pk %}" method="POST" id=""
enctype="multipart/form-data">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"> Edit Domain </h5>
<button type="button" class="close" data-dismiss="modal"><span>×</span>
</button>
</div>
<div class="modal-body">
<div class="basic-form">
<div class="form-group">
{% csrf_token %}
{{ form.errors }}
{{ form | crispy }}
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">submit</button>
</div>
</div>
</form>
</div>
</div>
this is inside for loop along with list items, I tried to fetch the instance as follows in get context data override, but it gives key error
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = get_object_or_404(Domain, kwargs={'pk': self.kwargs['pk']})
form = DomainEditForm(self.request.POST or None, instance=obj)
context['form'] = form
return context

How to add spaces between lines and align elements in the same column in InlineCheckboxes of crispy-form (Django)?

I have a form field which is CheckboxSelectMultiple and I use InlineCheckboxes from crispy-forms to make all those check boxes inline. Since I don't have the image of it I will use code snippet as an example.
this is how I want the form looks like in html and I will use stars instead of boxes
*name1 *name2 *name3 *name4
*name5 *name6 *name7 *name8
*name9 *name10 *name11 *name13
What can I do to add more spaces between each line and make it aligns vertically like shown above?
here is my forms.py
class AttendanceForm(forms.ModelForm):
class Meta:
model = Attendance
fields = ['student',]
widgets = {'student': forms.CheckboxSelectMultiple()}
def __init__(self, class_pk, current_user, *args, **kwargs):
super(AttendanceForm, self).__init__(*args, **kwargs)
current_student = Class.objects.get(id=class_pk)
self.helper = FormHelper(self)
self.fields['student'].queryset = current_student.student.order_by('first_name')
self.helper.layout = Layout(
InlineCheckboxes('student')
)
my current html. (it's not aligned perfectly as shown above!)
<form method="POST" class="ml-auto mr-auto">
{% csrf_token %}
<div style="text-align: justify;">{% crispy form form.helper %}</div>
<button
type="submit"
class="btn btn-success btn-sm"
style="font-size: 15px"
>
Check
</button>
</form>
Thanks before hand!
Now all I want to do is to make all elements display inline and add spaces to each line if it has more than one line. So I don't need to use crispy form for that. I remove the all crispy form tags from template and form class then in template all i need to do is:
<form method="POST" class="ml-auto mr-auto">
{% csrf_token %}
<div class="row mt-2 ml-auto mr-auto">
{% for form in form.student %}
<div class="col-md-4">
<h6 class="ml-2 mt-2" id="info-text">
{{ form.tag }} {{ form.choice_label }}
</h6>
</div>
{% endfor %}
</div>
<button
type="submit"
class="btn btn-success btn-sm"
style="font-size: 15px"
>
Check
</button>
</form>

Django edit view does not show

I am new to Django.
My app allows a user to create a project by providing a title and a body content, delete it and update it.
Now, I am creating and edit/update view for my app but it is not showing up in my html page.
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('allprojects', views.allprojects, name='allprojects'),
path('createproject', views.createproject, name='createproject'),
path('<int:project_id>', views.projectdetail, name='projectdetail'),
path('<int:project_id>/editproject', views.editproject, name='editproject'),
]
projects/views.py
#login_required
def editproject(request, project_id):
if request.method == 'POST':
if request.POST['title'] and request.POST['content']:
project = get_object_or_404(Project, pk=project_id)
project.title = request.POST['title']
project.content = request.POST['content']
project.developer = request.user
project.save()
return redirect('/projects/' + str(project.id))
else:
return render(request, 'projects/editproject.html', {'error':'All fields are required.'})
else:
return render(request, 'projects/allprojects.html')
projects/templates/projects/editproject.html
{% extends 'base.html' %}
{% block title %}Edit Project{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="mt-4 offset-md-3 col-md-6">
<h2>Create a new project</h2>
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="exampleFormControlTextarea1">Title of the project</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="1" name="title"></textarea>
</div>
<div class="form-group">
<label for="exampleFormControlTextarea1">Brief description of this project</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="5" name="content"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
{% endblock %}
PROBLEM
When I go to a urls such as http://localhost:8000/projects/2/editproject there is not the update form I want, the page exists but it contains nothing
You have to pass the project = get_object_or_404(Project, pk=project_id) in the dictionary in order to get the value in template.
Change your view like this:
#login_required
def editproject(request, project_id):
project = get_object_or_404(Project, pk=project_id)
if request.method == 'POST':
if request.POST['title'] and request.POST['content']:
project.title = request.POST['title']
project.content = request.POST['content']
project.developer = request.user
project.save()
return redirect('/projects/',project.project_id)
return render(request, 'projects/editproject.html', {'error':'All fields are required.','project':project})
And in the template you can get value like this :
Also in your template change method=put to method=post
and also you need to provide action if you want to update.
<div class="form-group">
<label for="exampleFormControlTextarea1">Title of the project</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="1" name="title">
{{project.title}}
</textarea>
</div>

Delete object with form in django

I'm displaying a table. In every line there should be a delete button which deletes the element from the table.
My problem is, I'm not sure how to pass the id of the element to the view.
html:
{% for post in posts %}
<div>
<h3>Zuletzt ausgewählt:</h3>
<p>published: <b>{{ post.pub_date }}</b>
</p>
<p>
name: <b>{{ post.Name }}</b>
anmeldung: <b>{{ post.get_Anmeldung_display }}</b>
essen: <b>{{ post.get_Essen_display }}</b>
<form action="" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" name="delete" type="submit" value="Löschen"/>
</form>
</p>
<p>
Email: <b>{{ post.Email }}</b>
</p>
</div>
{% endfor %}
views.py
if request.method == 'POST' and 'delete' in request.POST:
Eintrag.objects.filter(pk=id).delete()
return HttpResponseRedirect(request.path)
So I need to pass post.pub_date of every post to the view, how can I accomplish that?
My problem is, I'm not sure how to pass the id of the element to the view.
I can think of two ways to do this. I'll cover them both one by one.
1. Create a separate url route in your app specifically for deleting objects:
('/post/<pk>/delete/', name="delete_post"),
Then point your form's action to this url:
<form action="{% url 'delete_post' post.pk %}" method="POST">
...
Finally, modify your view function to accept the pk argument:
def my_view(request, pk):
...
2. Second method is to just create another field in your form and pass it the pk of the object:
Just create another field in your form.
<form action="" method="POST">
<input type="hidden" value="{{ post.pk }}" name="pk">
...
Then in your view just look at request.POST['pk'] to get the pk of the post.
A non-ajax way which is super easy to implement as it uses the Django generic views is this:
template.html
{% for post in posts %}
<div>
<h3>Zuletzt ausgewählt:</h3>
<p>published: <b>{{ post.pub_date }}</b>
</p>
<p>
name: <b>{{ post.Name }}</b>
anmeldung: <b>{{ post.get_Anmeldung_display }}</b>
essen: <b>{{ post.get_Essen_display }}</b>
<form action="" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" name="delete" type="submit" value="Löschen"/>
</form>
</p>
<p>
Email: <b>{{ post.Email }}</b>
</p>
<a href="/deleteurl/{{ post.pk }}">
Delete this!
</a>
</div>
{% endfor %}
Once the user clicks on the delete link they will be redirected to the delete view and template which will have a URL that looks like this "/deleteurl/1/".
Then your set of views, url, and template for processing the delete could look like this:
views.py
class DeleteMe(generic.DeleteView):
template_name = 'deleteconfirmation.html'
model = YourModel
success_url = '/YourRedirectUrl/'
urls.py
url(r'^deleteurl/(?P<pk>\d+)/$',
views.DeleteMe.as_view(), name='deletemeview'),
deleteconfirmation.html
<form action="" method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" />
</form>
Again, this is without the use of Ajax.
The views and template are taken directly from the Django Docs
Using POST is our priority, but I thought that adding another form will be redundant.
Found solution in django-allauth' email view.
Though it doesn't include confirmation step (as in docs, mentioned by #HoneyNutIchiros or in more details, or via onclick), it can be useful.
They add name (action_remove) to button and check it in the request.POST dict:
# account/email.html
<button type="submit" name="action_primary" >{% trans 'Make Primary' %}</button>
<button type="submit" name="action_send" >{% trans 'Re-send Verification' %}</button>
<button type="submit" name="action_remove" >{% trans 'Remove' %}</button>
...
<button name="action_add" type="submit">{% trans "Add E-mail" %}</button>
# account/views.py
class EmailView(AjaxCapableProcessFormViewMixin, FormView):
...
def post(self, request, *args, **kwargs):
...
if "action_add" in request.POST:
res = super(EmailView, self).post(request, *args, **kwargs)
elif "action_remove" in request.POST:
res = self._action_remove(request)
...
return res

Crispy-forms form.name renders rubbish

I'm trying to render a form but the {{form.name}} renders rubbish. The problem is that I can't even debug this to figure where the thing gets crooked.
The form:
class ActionItemForm(forms.ModelForm):
class Meta:
model = ActionItem
fields = ('project', 'portfolio', 'name', 'description', 'resolution', 'parent', 'priority', 'status', 'assignee', 'due_date')
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout()
super(ActionItemForm, self).__init__(*args, **kwargs)
The view:
def action_item_actions(request, action_item_id, action_code):
def enrich_form(wf_item, form):
form.id = 'edit_action_item'
form.name = form.id
form.title = wf_item.name
form.action = '/forms/action_item/edit/%s' % action_item_id
return form
action_item = ActionItem.objects.get(id=action_item_id)
wf_item = action_item.wf_get_action_by_code(action_code)
if wf_item:
if wf_item.trans_to:
form = ActionItemForm(instance=action_item, initial={action_item.get_wf_field(): type(getattr(action_item, action_item.get_wf_field())).objects.get(id=wf_item.trans_to)})
else:
form = ActionItemForm(instance=action_item)
form = enrich_form(wf_item, form)
for field in form.Meta.fields:
if field not in wf_item.fields:
form.helper.layout.fields.append(Field(field, type='hidden'))
return render_to_response('forms/modal_form.html', {'form': form}, template.RequestContext(request))
else:
return render_to_response('forms/message.html', {'message': Message('Error', 'WF Descriptor not found')}, template.RequestContext(request))
When the form exists the view, the form.name is correct:
Now when the form enters the template, it's still ok:
The view is quite simple:
{% load crispy_forms_tags %}
<form id="{{ form.id }}" role="form" class="small" name="{{ form.name }}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">{{ form.title }}</h4>
</div>
<div class="modal-body">
{% crispy form %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="button" class="btn btn-primary" value="Save" id="" onclick="submit_form('{{ form.id }}','{{ form.action }}')">
</div>
</div>
</div>
</form>
However, the form tag is rendered as this:
<form id="edit_action_item" role="form" class="small" name="<input id="id_name" maxlength="256" name="name" type="text" value="Test action item" />">
How can I track down where this gets broken? I kind of suspect that it gets broken because form may be potentially mixing the 'name' field with the form.name attribute.
You have field name in your form. So {{ form.name }} returns output for field name. You can put form name to other variable in __init__:
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout()
super(ActionItemForm, self).__init__(*args, **kwargs)
self.form_name = self.name # this line added
and call {{ form.form_name }} in template
<section class="form">
<h5>Contact Form</h5>
<h6>Let Us Know</h6>
<form action="{% url 'web:contact' %}" method="post" class="ajax">
{% csrf_token %}
<p class="left">
<label for="{{form.name.label.id_for_label}}">
{{form.name.label}}
{% if form.name.field.required %}
<small class="star">*</small>
{% endif %}
</label>
{{form.name}}
{% if form.name.errors %}
<span class="error">{{form.name.errors.as_text}}</span>
{% endif %}
</p>
</form>
</section>