Can't get POST data from Django form - django

I have a form involving just two textareas and I'm trying to POST them. However, I'm having difficulty trying to get the POST data from my view. Here's what I have so far in my template:
{% block title %}
<form method="post">
<strong>Title:</strong>
<div>
<textarea contenteditable id="id-title" name="title"></textarea>
</div>
{% endblock title %}
{% block description %}
<strong>Description:</strong>
<div>
<textarea contenteditable id="id-description" name="description"></textarea>
</div>
</form>
{% endblock description %}
<button class="btn-primary" id="ok" url="{% url 'publish' id=id %}" type="submit">Publish</button>
view:
#ajax
#csrf_exempt
#admin_required
def publish(request, id):
title = request.POST.get('title')
desc = request.POST.get('description')
print title
print desc
...
But title and desc turn out to be None. My publish function is also an ajax function that does some other stuff when the button is pressed.

Try altering your form with action, and moving your submit inside the form, e.g.:
<form method="post" action="{% url 'publish' id=id %}">
{% block title %}
<strong>Title:</strong>
<div>
<textarea contenteditable id="id-title" name="title"></textarea>
</div>
{% endblock title %}
{% block description %}
<strong>Description:</strong>
<div>
<textarea contenteditable id="id-description" name="description"></textarea>
</div>
{% endblock description %}
<input id="ok" type="submit">
</form>

Related

ckeditor not saving changes django

I have a form where in one of the fields, I use the ckeditor. However when I submit the form, the changes in the ckeditor field is not being saved. In the model, I have changed the field to aRichTextField. I have installed "ckeditor" in my apps in settings as well.
I have also both tried to load these scripts in my template:
{% load static %}
<script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script>
<script type="text/javascript" src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script>
On top of that have I also tried to add the {{ form.media }} instead of the scripts but it does still not work.
I am using HTMX to dynamically update the form.
This is my form template right now
<form action='' method="POST" class="form" hx-post='' hx-swap='outerHTML'>
{% csrf_token %}
{{ form.media }}
<div class="form-group">
{% for field in form %}
{{ field }}
</div>
{% endfor %}
<br>
<div class='htmx-indicator'>Loading...</div>
<div class="text-center">
<button class='htmx-inverted-indicator' type='submit' >Save</button>
</div>
{% if message %}
<p>{{ message }}</p>
{% endif %}
</form>
Does anybody know why the form is not being saved?
EDIT
This is my view
#login_required
def book_update_view(request, id=None):
book = get_object_or_404(Book, id=id)
form = BookForm(request.POST or None, instance=book)
context = {
"form": form,
"object": book,
}
if form.is_valid():
form.save()
context['message'] = 'Saved!'
if request.htmx:
return render(request, "book/snippets/forms.html", context)
return render(request, "book/update.html", context)
Looks like there is a conflict between the CKEditor and HTMX. The below relies heavily on this answer. It makes the following changes:
Switches the HTMX labels to the button rather than the form
Applies an event
listener to the CKEditor - it does this via the {{field.label_tag}}
which is now included
Fixes up a misplaced tag
Try making your form something like this (don't forget to replace the name of the CKEditor field - you may need to check your source code to see how this is rendered):
<form method="post">
{% csrf_token %}
{{ form.media }}
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
var element = new CKEDITOR.dom.element( document.getElementById( '{{ form.NAMEOFCKEDITORFIELD.id_for_label }}' ) );
event.detail.parameters['{{ form.NAMEOFCKEDITORFIELD.html_name }}'] = element.getEditor().getData();
})
</script>
<div class="form-group">
{% for field in form %}
{{ field.label_tag }}:<br />{{ field }}
{% endfor %}
</div>
<br>
<div class='htmx-indicator'>Loading...</div>
<div class="text-center">
<button class='htmx-inverted-indicator' type='submit' hx-post="{% url 'book_update_view_name' book.id %}" hx-target="#{{form.id}}" hx-swap="outerHTML">Save</button>
</div>
{% if message %}
<p>{{ message }}</p>
{% endif %}
if you dont want extra get parameter which might give you a problem, you can put onclick on your submit button to have ckeditor transfer the data to your field. something like this :
<script>
function saveCK(){
let ckdata = CKEDITOR.instances.your_field_id.getData();
$('#your_field_id').val(ckdata);
}
</script>
yeah, sorry for the jquery, I'm not sure vanilla javascript equivalent.
and on your submit button, add
onclick="saveCK()"
One more option is to use hx-vals.
For example:
<button type='submit' hx-vals="js:{ {{ form.NAMEOFCKEDITORFIELD.name }}: CKEDITOR.instances['{{ form.NAMEOFCKEDITORFIELD.id_for_label }}'].getData()}" hx-post=POSTURL>Save</button>

How can form fields be rendered manually in django-bootstrap

I have django-bootstrap-datepicker-plus set up in my app. Upon completion, I noticed that my form fields are stacked on rows screenshot whereas I would love to manually render some of the fields on the same row. Although I know the reason for that is because the form is rendered using {% bootstrap_form form %}
Here is my rendered template code snippet below.
{% extends 'accounts/no_header_footer.html' %}
{% block content %}
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
<div class="profile-create-form-container">
<form class="profile-create-form" data-certificates-url="{% url 'ajax_load_certificates' %}"
data-grades-url="{% url 'ajax_load_grades' %}"
data-relationships-url="{% url 'ajax_load_relationships' %}" data-states-url="{% url 'ajax_load_states' %}"
enctype="multipart/form-data"
id="ProfileCreateForm"
method="POST" runat="server">
{% csrf_token %}
<fieldset class="form-group text-center">
<span class="navbar-brand">
<img alt="..." height="40px" src="..." width="40px">
Basic Information
</span>
</fieldset>
{% bootstrap_form form %}
<div class="container">
<div class="text-center">
<button class="btn btn-dark" type="submit">
<i class="fa fa-save"></i> Save and Continue
</button>
</div>
</div>
</form>
</div>
The question I have is, is it possible to render each form field manually?
I was able to solve this issue by using {% bootstrap_field field %} as explained in this doc

How to fix pagination after making a search for specific data in django_tables2

In my project I am using with success django_tables2 in order to achieve server side processing.
The only thing that I do not know how to handle is that after searching, for example by name in a template rendering clients for my application, the search despite the fact that gives some returned results based on the name, it is not working properly if the result records are spread in more than one page based on my pagination.
In other words, when I am clicking the 2 (second page of my returned results), the app is showing all the pages concerning the clients 1 2 3 ...45 next (as i want to reach the /clients/ url, and not the 1 2 next structure for only the custom search data.
This happening also when I am clicking the next and previous buttons.
One easy solution It could be to increase my pagination limit in order to show all the possible results in one page, but this solution is not proper for big result sets.
Is there any solution to avoid loading and showing all the pages in the search bar and only keeping the results of my custom search?
Below is my snippets.
url.py
url(r'^clients/$', views.client_list, name='client_list'),
models.py
class Client(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
surname = models.CharField(max_length=50, verbose_name="Surname")
activity = models.IntegerField(choices=ACTIVITY_OPTIONS, null=True,default=ACTIVE)
views.py
def client_list(request, template_name='clients/client_list.html'):
if request.method == 'POST':
search_string = request.POST['search_client']
current_client=Client.objects.filter(Q(activity=1) & Q(name=search_string)| Q(surname=search_string))
single_table=ClientTable(current_client)
RequestConfig(request).configure(single_table)
return render(request,template_name, {'single_table': single_table})
else:
clients=Client.objects.filter(activity=1)
table = ClientTable(clients)
RequestConfig(request).configure(table)
return render(request,template_name, {'table': table})
tables.py
class ClientTable(tables.Table):
class Meta:
#define the model
model = Client
exclude=('..')
template_name = 'django_tables2/bootstrap.html'
sequence = ("surname", "name",)
template
{% extends 'base.html' %}
{% load has_group %}
{% load render_table from django_tables2 %}
{% load bootstrap3 %}
{% load static %}
{% load staticfiles %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12">
<form class="well" method="post" action="">
{% csrf_token %}
Client Search:<br>
<input type="text" class="form-control" id="search" name="search_client">
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "like" %} Submit
</button>
{% endbuttons %}
</form>
{% if single_table %}
{% render_table single_table %}
{% endif %}
{% if table %}
{% render_table table %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
Finally after searching I found a solution.
Django filters https://django-filter.readthedocs.io/en/master/index.html can be used in situations like this one.
The steps I followed are:
1) import the 'django_filters', to settings.py
2) Define the filters.py
import django_filters
from .models import Patient
class ClientFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Client
fields = ['id','name','surname']
3) Modify the views.py
class FilteredClientListView(SingleTableMixin, FilterView):
table_class = ClientTable
model = Client
template_name ='clients/client_list2.html'
filterset_class = ClientFilter
4) Modify urls.py accordingly since I used class based function
url(r'^clients2/$', views.FilteredClientListView.as_view(), name='client_list2'),
5) Modify my template
{% extends 'base.html' %}
{% load has_group %}
{% load render_table from django_tables2 %}
{% load bootstrap3 %}
{% load static %}
{% load staticfiles %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12">
<form class="well" method="post" action="">
{% csrf_token %}
Client Search:<br>
<input type="text" class="form-control" id="search" name="search_client">
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "like" %} Submit
</button>
{% endbuttons %}
</form>
{% if filter %}
<form action="" method="get" class="form form-inline">
{% bootstrap_form filter.form layout='inline' %}
{% bootstrap_button 'filter' %}
</form>
{% endif %}
{% if single_table %}
{% render_table single_table %}
{% endif %}
{% if table %}
{% render_table table %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
P.S : importing in the views.py the appropriate tables and filters

Page stall when passing data

I am trying to pass some data between pages, but it's not working. Any tips? I click submit and it takes me to a blank page. If I refresh then it shows my base template styles, but no data is passed.
index.html
{% extends "polls/base.html" %}
{% block title %}Vote{% endblock %}
{% block content %}
<h1>Welcome</h1>
<form action="/polls/" method="post">{% csrf_token %}
<p><label for="pin">Enter group pin:</label>
<input id="pin" type="text" name="pin" maxlength="4" />
<input type="submit" value="View Polls" /></p>
</form>
Moderator login
</p>
{% endblock %}
polls/index.html
{% extends "polls/base.html" %}
{% block title %}Recent Polls{% endblock %}
{% block content %}
{{ pin }}
{% endblock %}
polls/urls.py
url(r'^$',
ListView.as_view(
model=Poll,
template_name='polls/index.html')),
You need to write a view to handle the form submision. The view that works, is listing all your Polls. I recommend you to read the tutorial:
Basic views: https://docs.djangoproject.com/en/1.4/intro/tutorial03/
Form submission: https://docs.djangoproject.com/en/1.4/intro/tutorial04/
Basically, your form will send the data to another URL that will handle the processing of your data.
You must specify it in the action attribute:
<form action="/polls/create-poll" method="post">{% csrf_token %}
<input type='text' name='poll-name' />
<input type='submit' />
</form>
and in your views:
def create_poll(request):
poll_name = request.POST.get('poll-name')
poll = Poll.objects.create(name=poll_name)
return HttpResponse("Poll created")
I don't want to sound rude. But you should start with some HTTP and HTML tutorial. A good web programmer is the one that knows the basic stuff in detail. HTTP is a great protocol, try to learn it all the way through.

Why is this django formset not being submitted?

i have a formset as follows:
EduFormSet = formset_factory(forms.CandidateDegreeForm, can_delete=True)
edu_formset = EduFormSet(prefix='candidate_degree')
in the templates i am doing the following:
{% if edu_formset %}
{% for form in edu_formset %}
<div class="formset-form" style="visibility: visible;">
<form id="{{ form.prefix }}" method="POST" action="/degree/add/">
<h4>Some Heading Here</h4>
{% csrf_token %}
{% for field in form %}
{% include "form_field.html" %}
{% endfor %}
</form>
<script type="text/javascript">
jQuery(document).ready ( function(){
jQuery('{{ form.prefix }}').validationEngine();
});
</script>
<div class="clearfix"></div>
</div>
{% endfor %}
{{ edu_formset.management_form }}
<div class="button-container right">
<input class="button" type="submit" value="submit" />
</div>
{% endif %}
I am not sure why but nothing really happens when i hit the submit button.
Your submit button is not within the form, so the action is not triggered by the click!
Here's how the docs show you to render formsets:
<form method="post" action="">
<!-- Notice how the formset (below) and thus its submit button
is INSIDE the form (above) -->
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
You try to create multiple forms with the form.prefix for id. This could work but each form would have to be rendered with its own submit button. Formsets are designed to combine multiple forms into one and guarantee uniqueness of value names by said prefix. They would be enclosed in a singe form and share any submit triggers.