Django : modelformset not reflecting initial data - django

i am trying to create a form to edit skills of user where they have saved multiple no. of skills. after rendering the template input fields are empty but the no. of form created is correct as per queryset.
forms.py
class skillform(forms.ModelForm):
name = forms.CharField(label='Skill',widget=forms.TextInput(attrs={'class': 'form-control',}))
level = forms.ChoiceField(choices=(('Novice','Novice'),('Beginner','Beginner'),('Skillful','Skillful'),('Experienced','Experienced'),('Expert','Expert')),label="level",initial='Skillful',widget=forms.Select(),required=False)
class Meta:
model = userskills_model
fields = ('name','level')
skillformset = modelformset_factory(userskills_model, form = skillform, extra=0, can_delete=False)
models.py
class userskills_model(models.Model):
userid = models.ForeignKey(user_model, on_delete=models.PROTECT)
skills =models.CharField(max_length=264,unique=False,blank=False,null=False)
skills_level = models.CharField(max_length=264,unique=False,blank=False,null=False)
def __str__(self):
return str(self.userid)
views.py
def skillview(request):
qset=userskills_model.objects.filter( userid=user_model.objects.get(userid=userid))
skillformset(queryset = qset)
if request.method == 'GET':
formset = skillformset(request.GET or None)
elif request.method == 'POST':
formset = skillformset(request.POST)
#validating and saving
return render(request, template_name, {
'formset': formset,
})
template/skills.html
{% extends 'app/base.html' %}
{% load staticfiles%}
{% block head %}
<link href="{% static "/css/skills.css" %}" rel="stylesheet"
type="text/css"/>
{% endblock %}
{% block content %}
<div class="heading_text">SKILLS</div>
<form class="form-horizontal" method="POST" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="row form-row spacer">
<div class="col-5">
<label>{{form.name.label}}</label>
<div class="input-group">
{{form.name}}
</div>
</div>
<div class="col-5">
<label>{{form.level.label}}</label>
<div class="input-group">
{{form.level}}
<!-- <div class="input-group-append">
<button class="btn btn-success add-form-row">+</button>
</div> -->
</div>
</div>
<div class="input-group-append">
<button class="btn btn-success add-form-row">+</button>
</div>
</div>
{% endfor %}
<div class="row spacer">
<div class="col-3 button1">
<button type="submit" class="btn3">Save and Continue</button>
</div>
</div>
</form>
{% endblock %}
{% block custom_js %}
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script type="text/javascript">
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for",
$(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
var name = $(this).attr('name')
if(name) {
name = name.replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');}});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('-');
return false;}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;});
</script>
{% endblock %}
edit:added the template/skills.html . i m stuck with this please help me out here

The fields you have declared on your skillform do not exist on userskills_model so they won't be populated with anything. Try renaming the fields on your form to skills and skills_model so they match your model:
class skillform(forms.ModelForm):
skills = forms.CharField(label='Skill',widget=forms.TextInput(attrs={'class': 'form-control',}))
skills_level = forms.ChoiceField(choices=(('Novice','Novice'),('Beginner','Beginner'),('Skillful','Skillful'),('Experienced','Experienced'),('Expert','Expert')),label="level",initial='Skillful',widget=forms.Select(),required=False)
class Meta:
model = userskills_model
fields = ('skills','skills_level')
and update your template to reference form.skills and form.skills_level:
...
{% for form in formset %}
<div class="row form-row spacer">
<div class="col-5">
<label>{{form.skills.label}}</label>
<div class="input-group">
{{form.skills}}
</div>
</div>
<div class="col-5">
<label>{{form.skills_level.label}}</label>
<div class="input-group">
{{form.skills_level}}
...

I guess your qset is empty, try this -
qset=userskills_model.objects.filter( userid=self.request.user) # This for logged in user
For update case -
user = get_object_or_404(user_model, userid=userid)
qset=userskills_model.objects.filter( userid=user)

Related

formset function update view does not save the forms because the id is missing

I have a view to update 6 of my formset only that the click of the send button gives me the error that the id of each form is missing ... how do you fix it?
When I have to create formset there are never problems with the id...
Can anyone tell me where I'm wrong? I leave my code below
view
#login_required
def PianoSingleUpdateView(request, id):
piano = models.Piano.objects.get(single_piano__id = id)
piano_sett = models.PianoSingleDay.objects.get(id = id)
dato = models.PianoDay.objects.filter( piano_day = piano_sett)
DatiFormSet = modelformset_factory(models.PianoDay, extra = 0, fields=('id', 'kcal', 'carboidrati', 'proteine', 'grassi'))
if request.method == 'POST':
dati_formset = DatiFormSet(request.POST, request.FILES, queryset = dato)
if dati_formset.is_valid():
for dato in dati_formset:
dato.save()
return redirect('gestione-piano', id = piano.id)
else:
dati_formset = DatiFormSet(queryset = dato)
context = {'piano': piano, 'piano_sett': piano_sett, 'dati_formset': dati_formset}
return render(request, 'crud/update/update_piano_giornaliero.html', context)
models
class Piano(models.Model):
nome_piano = models.CharField(max_length=100)
data_inizio = models.DateField()
data_fine = models.DateField()
utente_piano = models.ForeignKey(
User,
on_delete = models.CASCADE,
related_name = 'utente_piano'
)
def __str__(self):
return self.nome_piano
class PianoSingleDay(models.Model):
giorni_settimana_scelta = [
("1","Lunedì"),
("2","Martedì"),
("3","Mercoledì"),
("4","Giovedì"),
("5","Venerdì"),
("6","Sabato"),
("7","Domenica")
]
giorni_settimana = models.CharField(
choices = giorni_settimana_scelta,
max_length = 300
)
single_piano = models.ForeignKey(
Piano,
on_delete = models.CASCADE,
related_name = 'single_piano'
)
def __str__(self):
return self.giorni_settimana
class PianoDay(models.Model):
scelta_pasto = [
("1","Colazione"),
("2","Spuntino mattina"),
("3","Pranzo"),
("4","Merenda"),
("5","Cena"),
("6","Spuntino sera")
]
pasto = models.CharField(
choices = scelta_pasto,
max_length = 300,
default = '-'
)
kcal = models.IntegerField(default = 0)
grassi = models.IntegerField(default = 0)
carboidrati = models.IntegerField(default = 0)
proteine = models.IntegerField(default = 0)
piano_day = models.ForeignKey(
PianoSingleDay,
on_delete = models.CASCADE,
related_name = 'piano_day'
)
file html
<form method="post" novalidate autocomplete="off" class="form-not-box">
{% csrf_token %}
<div class="box-schede">
<div class="alert alert-pop-up mt-3" role="alert">
Le colonne lasciate a 0 non verranno considerate.
</div>
{{ dati_formset.management_form }}
<div class="row mt-3">
{% for dati in dati_formset %}
<div class="col-lg-2">
<div class="info-piano">
<div class="ico">
{% if forloop.counter == 1 %}
<object type="image/svg+xml" data="{% static 'img/icone/colazione.svg' %}">
Icona colazione
</object>
{% elif forloop.counter == 3 %}
<object type="image/svg+xml" data="{% static 'img/icone/pranzo.svg' %}">
Icona pranzo
</object>
{% elif forloop.counter == 5 %}
<object type="image/svg+xml" data="{% static 'img/icone/cena.svg' %}">
Icona cena
</object>
{% elif forloop.counter == 2 or forloop.counter == 4 or forloop.counter == 6 %}
<object type="image/svg+xml" data="{% static 'img/icone/merenda.svg' %}">
Icona cena
</object>
{% endif %}
</div>
<div class="form-floating mb-3 mt-3">
{{ dati.kcal|add_class:'form-control'|append_attr:"placeholder: dati" }}
{{ dati.kcal.label_tag }}
</div>
<div class="form-floating mb-3">
{{ dati.carboidrati|add_class:'form-control'|append_attr:"placeholder: dati" }}
{{ dati.carboidrati.label_tag }}
</div>
<div class="form-floating mb-3">
{{ dati.proteine|add_class:'form-control'|append_attr:"placeholder: dati" }}
{{ dati.proteine.label_tag }}
</div>
<div class="form-floating">
{{ dati.grassi|add_class:'form-control'|append_attr:"placeholder: dati" }}
{{ dati.grassi.label_tag }}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="buttons mb-3">
Indietro
<input type="submit" class="btn btn-warning" value="Aggiorna piano">
</div>
</form>
My observation tells me that your problem is the DatiFormSet fields which shouldn't contain id value and also your function view had in queryset = dato which is not needed, but in some cases you should add an instance of Piano.
#login_required
def PianoSingleUpdateView(request, id):
piano = models.Piano.objects.get(single_piano__id = id)
piano_sett = models.PianoSingleDay.objects.get(id = id)
dato = models.PianoDay.objects.filter( piano_day = piano_sett)
DatiFormSet = modelformset_factory(models.PianoDay, extra = 0, fields=('kcal', 'carboidrati', 'proteine', 'grassi'))
if request.method == 'POST':
dati_formset = DatiFormSet(request.POST, request.FILES , instance=piano)
if dati_formset.is_valid():
for dato in dati_formset:
dato.save()
return redirect('gestione-piano', id = piano.id)
else:
dati_formset = DatiFormSet(request.POST)
context = {'piano': piano, 'piano_sett': piano_sett, 'dati_formset': dati_formset}
return render(request, 'crud/update/update_piano_giornaliero.html', context)

Django nested forms

I have trouble figuring out how to create nested forms. I have two models: Poll and Question (foreign key for Poll is inside Question model). I want it to be possible to add several questions for the poll dynamically inside one form. I've already tried making it work with inlineform_factory, but found troubles saving the form. Right now I have overcomplicated code that throws MultiValueDictError after saving the poll for the second time. I thought maybe there is some other way. Here's my code
models.py
class Question(models.Model):
type_choices = (
('text', 'Текстовый'),
('integer', 'Числовой'),
)
type = models.CharField(verbose_name=u'Тип вопроса', choices=type_choices, max_length=70)
text = models.CharField(verbose_name=u'Текст вопроса', max_length=255)
poll = models.ForeignKey('Poll', on_delete=models.CASCADE, related_name='questions')
class Poll(BaseFields):
objects = models.Manager()
published = PublishedManager()
title = models.CharField(verbose_name=u'Заголовок', max_length=70)
date_from = models.DateTimeField(u'Дата начала')
date_to = models.DateTimeField(u'Дата окончания')
status = models.IntegerField(choices=Status.choices, default=0)
def status_name(self):
return dict(Status.choices).get(self.status)
def update_url(self):
return reverse('poll_update', args=(self.id, ))
forms.py
QuestionInlineFormSet = inlineformset_factory(Poll, Question, extra=1, can_delete=False,
fields=('type', 'text', 'poll'),
widgets={
'type': w.Select(attrs={'class': 'form-control'}),
'text': w.TextInput(attrs={'class': 'form-control'}),
})
class PollForm(CommonForm):
class Meta(CommonForm.Meta):
model = Poll
views.py
class Create(BaseCreateView):
template_name = 'back/poll/poll.html'
page_title = 'Создание опроса'
model = Poll
form_class = PollForm
def form_valid(self, form):
result = super(Create, self).form_valid(form)
questions_formset = QuestionInlineFormSet(data=form.data, instance=self.object, prefix='questions_formset')
if questions_formset.is_valid():
questions_formset.save()
return result
def get_context_data(self, **kwargs):
context = super(Create, self).get_context_data(**kwargs)
context['questions_formset'] = QuestionInlineFormSet(prefix='questions_formset')
return context
class Update(BaseUpdateView):
template_name = 'back/poll/poll.html'
page_title = 'Редактирование опроса'
model = Poll
form_class = PollForm
def form_valid(self, form):
result = super(Update, self).form_valid(form)
questions_formset = QuestionInlineFormSet(data=form.data, instance=self.object, prefix='questions_formset')
if questions_formset.is_valid():
questions_formset.save()
return result
def get_context_data(self, **kwargs):
context = super(Update, self).get_context_data(**kwargs)
context['questions_formset'] = QuestionInlineFormSet(instance=self.get_object(), prefix='questions_formset')
return context
poll.html
{% extends 'back/base/form/base.html' %}
{% block form %}
{% include "back/includes/status_buttons.html" %}
<div class="row">
<div class="col-md-7">
<div class="row" style="margin-bottom: 15px;">
<div class="col-md-12">
{% include 'back/includes/status_label.html' %}
</div>
</div>
{% include "back/base/form/field.html" with field=form.title %}
{% include "back/base/form/datetime_field.html" with field=form.date_from %}
{% include "back/base/form/datetime_field.html" with field=form.date_to %}
{{ questions_formset.management_form }}
{% for question_form in questions_formset %}
{% include "back/poll/question.html" with form=question_form %}
{% endfor %}
<div style="float: right; margin-right: 45px">
<button class="btn btn-success add-form-row">Добавить вопрос</button>
</div>
</div>
</div>
{% endblock %}
question.html
<div class="questions">
<div class="row form-row">
<div class="form-group col-md-5{% if form.type.errors %} has-error{% endif %}">
<label>{{ form.type.label }}</label>
{{ form.type }}
<p class="help-block">{{ form.type.errors }}</p>
</div>
<div class="form-group col-md-5{% if form.text.errors %} has-error{% endif %}">
<label>{{ form.text.label }}</label>
{{ form.text }}
<p class="help-block">{{ form.text.errors }}</p>
</div>
<div class="col-md-2" style="margin-top: 25px">
<button type="button" class="btn btn-danger remove-form-row">✕</button>
</div>
</div>
</div>
<script>
function updateElementIndex(el, prefix, ndx) {
let id_regex = new RegExp('(' + prefix + '-\\d+)');
let replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function deleteForm(prefix, btn) {
let total = parseInt($('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val());
if (total > 1) {
btn.closest('.form-row').remove();
let forms = $('.form-row');
$('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val(forms.length);
for (let i = 0, formCount = forms.length; i < formCount; i++) {
$(forms.get(i)).find(':input').each(function () {
updateElementIndex(this, prefix, i);
});
}
}
}
function cloneMore(selector, prefix) {
let newElement = $(selector).clone(true);
let total = $('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function () {
let name = $(this).attr('name').replace('-' + (total - 1) + '-', '-' + total + '-');
let id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
});
newElement.find('label').each(function () {
let forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total - 1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
}
$(document).on('click', '.add-form-row', function (event) {
event.preventDefault();
cloneMore('.form-row:last', 'questions');
})
$(document).on('click', '.remove-form-row', function (event) {
event.preventDefault();
deleteForm('questions', $(this));
});
</script>
Here's a photo of what it should look like
Again, I want it to be possible to add questions, remove them, save the form. And after I click on the poll in the list of all polls and go to it's edit page I want already added questions to be there.
UPDATE
Found solution to MultiValueDictKeyError in this post
How to debug a Django MultiValueDictKeyError on Formset POST
Now the only problem I have is removing Questions from Poll. My delete button works, it removes the form from page, but after saving the document it reappears.

See all chat rooms that user has in django-channels

I am making a website, this website has a chat app include, the chat app works perfect, but there is a thing I want to do but I dont know how to do it.
So I have this chat view chat view, here is were there is the websocket and all that stuff,
But in this view this view, is the place were I want the user to see all the chat rooms he is in, on the side of chats like the two example users that are in there. the problem is that I don´t know how to do it. can someone tell me how to do it? with a simple example, like a very simple chat, that the chats of the user appear in the home page?, thanks for the help.
My code:
Chat room html or thread:
{% extends "base.html" %}
{% block content %}
<section class="msger" id="prueba">
<header class="msger-header">
<div class="msger-header-title">
<i id="The_other_user"></i>{% if user != object.first %}{{ object.first }}{% else %}{{ object.second }}{% endif %}
</div>
<div class="msger-header-options">
<span><i class="fas fa-comment-alt"></i></span>
</div>
</header>
<main class="msger-chat">
<div class="msg left-msg">
<div
class="msg-img"
style="background-image: url(https://image.flaticon.com/icons/svg/327/327779.svg)"
></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">BOT</div>
<div class="msg-info-time"></div>
</div>
<div class="msg-text">
Hola, bienvenid# al Chat! Manda un mensaje para tener cita con la Consultora. Puedes mirar el boton de como pedir consulta😄
</div>
</div>
</div>
{% for chat in object.chatmessage_set.all %}
<div class="msg right-msg" class="msg">
<div class="msg-img" style="background-image: url(https://cdn.xl.thumbs.canstockphoto.com/user-icon-person-profile-sign-vector-avatar-illustration-office-human-web-symbol-business-man-image_csp63452775.jpg)"></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">{{ chat.user }}</div>
<div class="msg-info-time"></div>
</div>
<div class="msg-text">{{ chat.message }}</div>
</div>
</div>
{% endfor %}
</main>
<form id='form' method='POST' class="msger-inputarea"> {% csrf_token %}
<input type='hidden' id='myUsername' value='{{ user.username }}' />
{{ form }}
<input type="submit" class="msger-send-btn">
</form>
</section>
<!--The Back button and Help-->
<i class="fa fa-arrow-left"></i>
<a class="tooltip demo" href="" data-tooltip="Empieza por decir tu nombre completo, despues di la razon de una consulta, di cuantos familiares niños tienes y tambien menciona cuanto tiempo llevas con ese problema. Seras respondid# en menos de 2 dias">
Como pedir consulta
</a>
{% endblock %}
{% block script %}
<script src='https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.js'>
</script>
<script>
// websocket scripts
// console.log(window.location)
var loc = window.location
var formData = $("#form")
var msgInput = $("#id_message")
var chatHolder = $("#chat-items")
var me = $("#myUsername").val()
var he = $("#The_other_user")
var user = $(".msg-info-name").text();
const PERSON_IMG = "https://cdn.xl.thumbs.canstockphoto.com/user-icon-person-profile-sign-vector-avatar-illustration-office-human-web-symbol-business-man-image_csp63452775.jpg";
const msgerChat = $(".msger-chat");
const msger = $(".msger");
var wsStart = 'ws://'
if (loc.protocol == 'https:') {
wsStart = 'wss://'
}
var endpoint = wsStart + loc.host + loc.pathname + '/'
var socket = new ReconnectingWebSocket(endpoint)
socket.onmessage = function(e){
console.log("message", e)
var chatDataMsg = JSON.parse(e.data)
// chatHolder.append("<li>" + chatDataMsg.message + " via " + chatDataMsg.username + "</li>")
// Append the message frontend
var side_append = "msg right-msg";
if (chatDataMsg.username != me) {
var side_append = "msg left-msg";
};
msgerChat.append(`
<div class="${side_append}" class="msg">
<div class="msg-img" style="background-image: url(${PERSON_IMG})"></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">${chatDataMsg.username}</div>
<div class="msg-info-time">${formatDate(new Date())}</div>
</div>
<div class="msg-text">${chatDataMsg.message}</div>
</div>
</div>
`)
// Utils
msgerChat.scrollTop += 500;
function get(selector, root = document) {
return root.querySelector(selector);
}
function formatDate(date) {
const h = "0" + date.getHours();
const m = "0" + date.getMinutes();
return `${h.slice(-2)}:${m.slice(-2)}`;
}
scrollWin()
}
socket.onopen = function(e){
console.log("open", e)
formData.submit(function(event){
event.preventDefault()
var msgText = msgInput.val()
// chatHolder.append("<li>" + msgText + " via " + me + "</li>")
var finalData = {
'message': msgText
}
socket.send(JSON.stringify(finalData))
formData[0].reset()
})
}
socket.onerror = function(e){
console.log("error", e)
}
socket.onclose = function(e){
console.log("close", e)
}
window.onload = function() {
scrollWin()
}
//Scroll auto funct
const chatContainer = document.querySelector(".msger-chat");
function scrollWin() {
chatContainer.scrollTo(0, chatContainer.scrollHeight)
}
$( ".msg" ).each(function() {
var users = $(this).find(".msg-info-name").text();
if (users != me) {
$(this).removeClass("msg right-msg");
$(this).addClass("msg left-msg");
};
});
</script>
{% endblock %}
the messages room, were I want to see all users chat rooms:
{% load static %}
<!DOCTYPE html>
<head>
<title>Consultoria</title>
<script src="https://kit.fontawesome.com/e66aaa0c91.js" crossorigin="anonymous"></script>
<link rel='stylesheet' type='text/css' href="{% static 'css/chats.css' %}">
<link rel='stylesheet' type='text/css' href="{% static 'css/cards.css' %}">
<link rel='stylesheet' type='text/css' href="{% static 'css/buttons.css' %}">
<style>
a{text-decoration:none}
</style>
</head>
<body>
<!--The Message chats-->
<div class="container clearfix" style="position: fixed; left: 20px; top: 67px;">
<h1 style="position: relative; top: 17px; right: -75px;">CHATS</h1>
<div class="scrollable">
<ul class="list">
<a class="clearfix" href="#">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/195612/chat_avatar_01.jpg" />
<div class="about">
<div class="name">Vincent Portr</div>
<div class="status">
online
</div>
</div>
</a>
<a class="clearfix" href="#">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/195612/chat_avatar_02.jpg" />
<div class="about">
<div class="name">Aiden Chavez</div>
<div class="status">
offline
</div>
</div>
</a>
</ul>
</div>
</div>
<!--The Message chats-->
<!--The Consultors cards-->
<main class="page-content">
<div class="card">
<h1 class="subtitle">CONSULTORA FAMILIAR</h1>
<div class="content">
<h2 class="title">Marcela Santamaria</h2>
<p class="copy">Check out all of these gorgeous mountain trips with beautiful views of, you guessed it, the mountains</p><a class="btn" href="Marcela/">Contactar</a></div>
</div>
<div class="card">
<div class="content">
<h2 class="title">Coming Soon</h2>
<p class="copy">Más consultores vendrán pronto</p></div>
</div>
</main>
<!--The Consultors cards-->
<!--Back and help buttons-->
<i class="fa fa-home"></i>
<i class="fa fa-question"></i>
<!--Back and help buttons-->
</body>
</html>
my models:
from django.db import models
from django.conf import settings
from django.db import models
from django.db.models import Q
class ThreadManager(models.Manager):
def by_user(self, user):
qlookup = Q(first=user) | Q(second=user)
qlookup2 = Q(first=user) & Q(second=user)
qs = self.get_queryset().filter(qlookup).exclude(qlookup2).distinct()
return qs
def get_or_new(self, user, other_username): # get_or_create
username = user.username
if username == other_username:
return None
qlookup1 = Q(first__username=username) & Q(second__username=other_username)
qlookup2 = Q(first__username=other_username) & Q(second__username=username)
qs = self.get_queryset().filter(qlookup1 | qlookup2).distinct()
if qs.count() == 1:
return qs.first(), False
elif qs.count() > 1:
return qs.order_by('timestamp').first(), False
else:
Klass = user.__class__
user2 = Klass.objects.get(username=other_username)
if user != user2:
obj = self.model(
first=user,
second=user2
)
obj.save()
return obj, True
return None, False
class Thread(models.Model):
first = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_first')
second = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_second')
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = ThreadManager()
#property
def room_group_name(self):
return f'chat_{self.id}'
def broadcast(self, msg=None):
if msg is not None:
broadcast_msg_to_chat(msg, group_name=self.room_group_name, user='admin')
return True
return False
class ChatMessage(models.Model):
thread = models.ForeignKey(Thread, null=True, blank=True, on_delete=models.SET_NULL)
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='sender', on_delete=models.CASCADE)
message = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
my consumers.py:
import asyncio
import json
from django.contrib.auth import get_user_model
from channels.consumer import AsyncConsumer
from channels.db import database_sync_to_async
from .models import Thread, ChatMessage
class ChatConsumer(AsyncConsumer):
async def websocket_connect(self, event):
print("connected", event)
other_user = self.scope['url_route']['kwargs']['username']
me = self.scope['user']
# print(other_user, me)
thread_obj = await self.get_thread(me, other_user)
self.thread_obj = thread_obj
chat_room = f"thread_{thread_obj.id}"
self.chat_room = chat_room
await self.channel_layer.group_add(
chat_room,
self.channel_name
)
await self.send({
"type": "websocket.accept"
})
# await asyncio.sleep(10)
async def websocket_receive(self, event):
# when a message is received from the websocket
print("receive", event)
front_text = event.get('text', None)
if front_text is not None:
loaded_dict_data = json.loads(front_text)
msg = loaded_dict_data.get('message')
user = self.scope['user']
username = 'default'
if user.is_authenticated:
username = user.username
myResponse = {
'message': msg,
'username': username,
}
await self.create_chat_message(user, msg)
# broadcast the message event to be send
await self.channel_layer.group_send(
self.chat_room,
{
"type": "chat_message",
"text": json.dumps(myResponse)
}
)
async def chat_message(self, event):
# sends the actual message
await self.send({
"type": "websocket.send",
"text": event['text']
})
async def websocket_disconnect(self, event):
# when the socket connects
print("disconnected", event)
#database_sync_to_async
def get_thread(self, user, other_username):
return Thread.objects.get_or_new(user, other_username)[0]
#database_sync_to_async
def create_chat_message(self, me, msg):
thread_obj = self.thread_obj
return ChatMessage.objects.create(thread=thread_obj, user=me, message=msg)
By looking at your models, in your views you can make a context and then in your messages room you can use that context with django template tag, to loop all the chat rooms of your user, try this:
all_rooms = Thread.objects.by_user(request.user)
context = {
'my_chats': all_rooms
}
this is an option I see that you try with your models

Django: How can I combine 2 formsets as one so as to display as one inline table (of course with pagination) in template

Say I have 3 models: Groups, Answers, and Questions (Group as ForeignKey and models are broken for normalization). I have created corresponding formsets for Answers and Questions for these models.
On selection of a group, my goal is to display related Answers and Questions in a inline table on form. Something like this:
I am able to get formsets in a template and display them in separate sections, but not able to display them as one table (I don't want to do this using HTML-JS). Is there any way I can pass the answer and question formsets as one context object so that they can be displayed as one table in the template?
Note: there may be 5 questions but only 3 answers for a group, or vice versa.
Also, it would be nice to add pagination to this inline table (or the formsets).
urls.py:
from django.conf.urls import url
from .views import lists, load_questions
from django.urls import path
urlpatterns = [
url(r'lists', lists, name="lists"),
path('ajax/load_questions/', load_questions, name='load_questions'),
]
I have as of now:
models.py:
from django.db import models
from django.utils.timezone import now
class Groups(models.Model):
class Meta:
verbose_name_plural = "Groups"
group = models.CharField(max_length=30)
group_description = models.CharField(max_length=4000,default=None,null=True)
group_date = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.group
def save(self,*args,**kwargs):
if(self.group and self.group_date is None):
self.group_date=now()
super(Groups,self).save(*args,**kwargs)
class Questions(models.Model):
class Meta:
verbose_name_plural = "Questions"
question = models.CharField(max_length=30,verbose_name="Input Question")
question_description = models.CharField(max_length=4000 ,default=None)
question_date=models.DateTimeField(blank=True,null=True)
question_group = models.ForeignKey(Groups, on_delete=models.CASCADE)
def __str__(self):
return self.question
def save(self,*args,**kwargs):
if(self.question and self.question_date is None):
self.question_date=now()
super(Questions,self).save(*args,**kwargs)
class Answers(models.Model):
class Meta:
verbose_name_plural = "Answers"
answer = models.CharField(max_length=100,verbose_name="Your Answer")
answers_description = models.CharField(max_length=4000,default=None,help_text="",blank=True,null=True)
answer_date = models.DateTimeField(blank=True, null=True)
answer_group = models.ForeignKey(Groups, on_delete=models.CASCADE,blank=True)
#valid_question = models.ManyToManyField("Questions",related_name="answers")
print("Model Called")
def __str__(self):
return self.answer
def save(self,*args,**kwargs):
if(self.answer and self.answer_date is None):
self.answer_date=now()
super(Answers,self).save(*args,**kwargs)
forms.py:
from django.forms import inlineformset_factory,Textarea,BaseFormSet
from django.forms.models import modelformset_factory
from .models import Groups,Questions,Answers
from django import forms
class groupForm(forms.Form):
group = forms.CharField(label="Group",max_length=100)
def choices(self):
a=[('','Select a Group')]
return a+[ (o.id, str(o)) for o in Groups.objects.all()]
def __init__(self, *args, **kwargs):
super(groupForm, self).__init__(*args, **kwargs)
print([(o.id, str(o)) for o in Groups.objects.all()])
print(type([(o.id, str(o)) for o in Groups.objects.all()]))
self.fields['group'] = forms.ChoiceField(
choices=self.choices(),
required=True,
)
#self.fields['group'].label = "Select Group"
from crispy_forms.helper import FormHelper, Layout
class questionForm(forms.ModelForm):
class Meta:
model = Questions
#fields = ['question', 'question_description',]
exclude = ()
questionFormSet = modelformset_factory(Questions, form=questionForm, extra=1)
class answerForm(forms.ModelForm):
class Meta:
model = Groups
exclude = ()
def add_fields(self, form, index):
"""A hook for adding extra fields on to each form instance."""
super(answerForm, self).add_fields(form, index)
# here call a custom method or perform any other required action
form.set_index(index)
#answerFormSet = modelformset_factory(Answers, form=answerForm, extra=1)
questionFormSet = inlineformset_factory(Groups, Questions,form=answerForm)
answerFormSet = inlineformset_factory(Groups, Answers,form=answerForm)
#myFormset=questionFormSet|answerFormSet
views.py:
from django.shortcuts import render, redirect
from .models import Answers, Questions, Groups
# Create your views here.
from .forms import groupForm,questionFormSet,answerFormSet
from django.http import JsonResponse
def lists(request):
if request.method == 'POST':
questionsform = questionFormSet(request.POST)
answersform = answerFormSet(request.POST)
groupsform = groupForm(request.POST)
print(answersform.is_valid())
print(answersform.errors.as_data())
if answersform.is_valid() and groupsform.is_valid() and questionsform.is_valid():
print("in views")
print(answersform.cleaned_data)
print(type(groupsform.cleaned_data))
a=Answers(answer=answersform.cleaned_data['answer'],
answers_description="",
answer_group=Groups(groupsform.cleaned_data['group']))
a.save()
q = Questions(question=questionsform.cleaned_data['question'],
question_description="",
question_group=Groups(groupsform.cleaned_data['group']))
q.save()
return redirect('lists')
else:
return redirect('chatbot_welcome')
else:
context = {
'groups': groupForm,
'questions': questionFormSet,
'answers': answerFormSet,
}
return render(request, 'lists.html', context)
def load_questions(request):
group_id = request.GET.get ('groupId')
data = {
"Table": {
"TR": [
]
}
}
if group_id is not None:
questions = (Questions.objects.filter(question_group=group_id).values("question", "question_group"))
answers = (Answers.objects.filter(answer_group=group_id).values("answer", "answer_group"))
l_len = len(questions) if len(questions) >= len(answers) else len(answers)#lambda can be used here
for i in range(l_len):
try:
if list(questions)[i]["question"]:
q=list(questions)[i]["question"]
except:
q=''
try:
if list(answers)[i]["answer"]:
a=list(answers)[i]["answer"]
except:
a=''
data["Table"]["TR"].append({
"row": i+1,
"group": group_id,
"question": q,
"Answer": a
})
print(data)
return JsonResponse(data)
else:
return JsonResponse(data)
Template:
{% extends "base.html" %}
{% load staticfiles %}
{% block content %}
{% load crispy_forms_tags %}
<form method="post" id="groupform" data-group-url="{% url 'load_questions' %}">
{% csrf_token %}
<div class="panel-group" id="accordion18" style="display: block;">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion18" href="#accBody20" id="accHeading20" class="">Groups</a>
</h4>
</div>
<div class="panel-collapse collapse in" id="accBody20" style="height: auto;">
<div class="panel-body">
<div class="row"><div class="col-md-12"><div class="form-group">
<div class="form-group">
{{ groups }}
Create a New Group
</div></div></div></div>
</div>
</div>
</div>
</div>
<div class="panel-group" id="accordion21" style="display: block;">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion21" href="#accBody23" id="accHeading23" class="">Questionnaires</a>
</h4>
</div>
<div class="panel-collapse collapse in" id="accBody23" style="height: auto;">
<div class="panel-body">
<div class="row"><div class="col-md-12"></div></div><div class="row"><div class="col-md-12"><div class="form-group">
<div class="panel-body">
<span>{{groups.group.name|title }}</span>:<span id="group">None</span>
{{questions.forms}}
{% for form in questions.forms %}
{% for field in form %}
field={{field}}
{% endfor %}
{% endfor %}
<table>
<thead>
{% for form in questions.forms %}
{% if forloop.first %}
{% for field in form %}
<th>{{ field.label_tag }}</th>
{% endfor %}
{% endif %}
</thead>
<tbody>
<tr>
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<table>
<thead>
{% for form in answers.forms %}
{% if forloop.first %}
{% for field in form %}
<th>{{ field.label_tag }}</th>
{% endfor %}
{% endif %}
</thead>
<tbody>
<tr>
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<!--
<form action="" method="post">
{% csrf_token %}
{% crispy questions %}{% crispy answers %}
</form>
-->
<input type="button" class="add-row" value="Add Row">
<button type="button" class="delete-row">Delete Row</button>
</div>
<div class="panel-body">
<div class="tbl_user_data"></div>
</div>
<button id="button40" type="submit" value="Submit" class="btn btn-primary">Submit</button></div></div></div></div>
</div>
</div>
</div>
</form>
<script>
var groupId=0;
$("#id_group").change(function () {
var url = $("#groupform").attr("data-group-url"); // get the url of the `load_cities` view
groupId = $(this).val(); // get the selected country ID from the HTML input
$('#group').text(groupId);
$.ajax({ // initialize an AJAX request
url: url,
//data: $("#groupform").serialize(),
dataType: 'json',// set the url of the request (= localhost:8000/hr/ajax/load-cities/)
data: {
'groupId': groupId // add the country id to the GET parameters
},
success: function (data) { // `data` is the return of the `load_cities` view function
var data1={
"Table": {
"TR": [
{
"row": 1,
"group": 1,
"question": "heyy",
"Answer": "hey"
},
{
"row": 2,
"group": 1,
"question": "y",
"Answer": "heyy"
},
{
"group": 1,
"row": 3,
"question": "How are you",
"Answer": "Fine"
}
]
}
}
//questions_list=JSON.parse(data.questions)[0].question;
//alert(questions_list)
//answers_list=JSON.parse(data.answers)[0].answer;
//alert(answers_list)
writeintoTable(data)
//alert('done')
}
});
});
function runOnLoad(){
//alert(1)
}
var random_id = function ()
{
var id_num = Math.random().toString(9).substr(2,3);
var id_str = Math.random().toString(36).substr(2);
return id_num + id_str;
}
function writeintoTable(data){
/*
$.each(data.Table.TR, function( index, json ) {
//alert(index +" -- "+ data.Table.TR[index].question)
$("#setupbody").append('<tr><td>'
+data.Table.TR[index].row+
'</td><td>'
+data.Table.TR[index].group+
'</td><td>'
+data.Table.TR[index].question+
'</td><td>'
+data.Table.TR[index].Answer+
'</td></tr>');
});*/
/*
for (i=0;i<=data.Table.TR;i++)
{
$("#setupbody").append('<tr><td></td><td>1</td><td>Hi</td><td>Hello</td></tr>');
}*/
var tbl = '';
tbl +='<table class="table table-hover">'
//--->create table header > start
tbl +='<thead>';
tbl +='<tr>';
tbl +='<th>Select</th>';
tbl +='<th>Row</th>';
tbl +='<th>Group</th>';
tbl +='<th>Question</th>';
tbl +='<th>Answer</th>';
tbl +='<th>Options</th>';
tbl +='</tr>';
tbl +='</thead>';
//--->create table header > end
//--->create table body > start
tbl +='<tbody>';
//--->create table body rows > start
$.each(data.Table.TR, function(index, val)
{
//you can replace with your database row id
var row_id = random_id();
//loop through ajax row data
tbl +='<tr row_id="'+row_id+'">';
tbl +='<td><input type="checkbox" value="" name="record" id="cb'+val['row']+'"></td>'
tbl +='<td ><div class="row_data" edit_type="click" col_name="rnum">'+val['row']+'</div></td>';
tbl +='<td ><div class="row_data" edit_type="click" col_name="fname">'+val['group']+'</div></td>';
tbl +='<td ><div class="row_data" edit_type="click" col_name="lname">'+val['question']+'</div></td>';
tbl +='<td ><div class="row_data" edit_type="click" col_name="email">'+val['Answer']+'</div></td>';
//--->edit options > start
tbl +='<td>';
tbl +='<span class="btn_edit" > <a href="#" class="btn btn-link " row_id="'+row_id+'" > Edit</a> </span>';
//only show this button if edit button is clicked
tbl +='<span class="btn_save"> Save | </span>';
tbl +='<span class="btn_cancel"> Cancel | </span>';
tbl +='</td>';
//--->edit options > end
tbl +='</tr>';
});
//--->create table body rows > end
tbl +='</tbody>';
//--->create table body > end
tbl +='</table>'
//--->create data table > end
//$("#dataTable").append(tbl);
$(document).find('.tbl_user_data').html(tbl);
$(document).find('.btn_save').hide();
$(document).find('.btn_cancel').hide();
}
//--->make div editable > start
$(document).on('click', '.row_data', function(event)
{
event.preventDefault();
if($(this).attr('edit_type') == 'button')
{
return false;
}
//make div editable
$(this).closest('div').attr('contenteditable', 'true');
//add bg css
$(this).addClass('bg-warning').css('padding','5px');
$(this).focus();
})
//--->make div editable > end
//--->save single field data > start
$(document).on('focusout', '.row_data', function(event)
{
event.preventDefault();
if($(this).attr('edit_type') == 'button')
{
return false;
}
var row_id = $(this).closest('tr').attr('row_id');
var row_div = $(this)
.removeClass('bg-warning') //add bg css
.css('padding','')
var col_name = row_div.attr('col_name');
var col_val = row_div.html();
var arr = {};
arr[col_name] = col_val;
//use the "arr" object for your ajax call
$.extend(arr, {row_id:row_id});
//out put to show
$('.post_msg').html( '<pre class="bg-success">'+JSON.stringify(arr, null, 2) +'</pre>');
})
//--->save single field data > end
//--->button > edit > start
$(document).on('click', '.btn_edit', function(event)
{
event.preventDefault();
var tbl_row = $(this).closest('tr');
var row_id = tbl_row.attr('row_id');
tbl_row.find('.btn_save').show();
tbl_row.find('.btn_cancel').show();
//hide edit button
tbl_row.find('.btn_edit').hide();
//make the whole row editable
tbl_row.find('.row_data')
.attr('contenteditable', 'true')
.attr('edit_type', 'button')
.addClass('bg-warning')
.css('padding','3px')
//--->add the original entry > start
tbl_row.find('.row_data').each(function(index, val)
{
//this will help in case user decided to click on cancel button
$(this).attr('original_entry', $(this).html());
});
//--->add the original entry > end
});
//--->button > edit > end
//--->button > cancel > start
$(document).on('click', '.btn_cancel', function(event)
{
event.preventDefault();
var tbl_row = $(this).closest('tr');
var row_id = tbl_row.attr('row_id');
//hide save and cacel buttons
tbl_row.find('.btn_save').hide();
tbl_row.find('.btn_cancel').hide();
//show edit button
tbl_row.find('.btn_edit').show();
//make the whole row editable
tbl_row.find('.row_data')
.attr('edit_type', 'click')
.removeClass('bg-warning')
.css('padding','')
tbl_row.find('.row_data').each(function(index, val)
{
$(this).html( $(this).attr('original_entry') );
});
});
//--->button > cancel > end
//--->save whole row entery > start
$(document).on('click', '.btn_save', function(event)
{
event.preventDefault();
var tbl_row = $(this).closest('tr');
var row_id = tbl_row.attr('row_id');
//hide save and cacel buttons
tbl_row.find('.btn_save').hide();
tbl_row.find('.btn_cancel').hide();
//show edit button
tbl_row.find('.btn_edit').show();
//make the whole row editable
tbl_row.find('.row_data')
.attr('edit_type', 'click')
.removeClass('bg-warning')
.css('padding','')
//--->get row data > start
var arr = {};
tbl_row.find('.row_data').each(function(index, val)
{
var col_name = $(this).attr('col_name');
var col_val = $(this).html();
arr[col_name] = col_val;
});
//--->get row data > end
//use the "arr" object for your ajax call
$.extend(arr, {row_id:row_id});
//out put to show
$('.post_msg').html( '<pre class="bg-success">'+JSON.stringify(arr, null, 2) +'</pre>')
});
//--->save whole row entery > end
$(".add-row").click(function(){
var question = $("#id_question").val();
//var group = $("#group").val();
var answer = $("#id_answer").val();
if (question=='' || question=='undefined'||answer=='' || answer=='undefined' )
{
alert('row not complete to add')
return false;
}
//var markup = "<tr><td><input type='checkbox' name='record'></td><td>" + name + "</td><td>" + email + "</td></tr>";
var tbl = '';
//you can replace with your database row id
var row_id = random_id();
//loop through ajax row data
tbl +='<tr row_id="'+row_id+'">';
tbl +='<td><input type="checkbox" value="" name="record" id="cb'+100+'"></td>'
tbl +='<td ><div class="row_data" edit_type="click" col_name="rnum">'+100+'</div></td>';
tbl +='<td ><div class="row_data" edit_type="click" col_name="fname">'+groupId+'</div></td>';
tbl +='<td ><div class="row_data" edit_type="click" col_name="lname">'+question+'</div></td>';
tbl +='<td ><div class="row_data" edit_type="click" col_name="email">'+answer+'</div></td>';
//--->edit options > start
tbl +='<td>';
tbl +='<span class="btn_edit" > <a href="#" class="btn btn-link " row_id="'+row_id+'" > Edit</a> </span>';
//only show this button if edit button is clicked
tbl +='<span class="btn_save"> Save | </span>';
tbl +='<span class="btn_cancel"> Cancel | </span>';
tbl +='</td>';
//--->edit options > end
tbl +='</tr>';
$("table tbody").append(tbl);
$(document).find('.btn_save').hide();
$(document).find('.btn_cancel').hide();
});
// Find and remove selected table rows
$(".delete-row").click(function(){
var r = confirm("Selected Row will be deleted.");
if (r == true) {
$("table tbody").find('input[name="record"]').each(function(){
if($(this).is(":checked")){
$(this).parents("tr").remove();
}
});
} else {
$("table tbody").find('input[name="record"]').each(function(){
if($(this).is(":checked")){
$(this).prop('checked', false);
}
});
alert("Row(s) not Deleted!");
}
});
</script>
{% endblock %}

u'ManagementForm data is missing or has been tampered with' with Django formset

I have three forms, depending on number of rooms i want to add or delete new fields "adult" and "children". For example: if value of field "room" will be 2, it should generate two couples another fields for each room 'adult' and 'children', but if change value from 2 on 1, it should delete one couple of fields. And when change the value of 'room' field from 2 to 3, it should add one couple of fields.
My forms.py:
class HotelForm(forms.Form):
rooms = forms.IntegerField(label=(u'Rooms'), min_value=1)
class TouristsForm(forms.Form):
adult = forms.IntegerField(label=(u'Adults'), min_value=1, initial=1)
children = forms.IntegerField(label=(u'Children'), min_value=0, initial=0, required=False)
class ChildrenAgeForm(forms.Form):
children_age = forms.IntegerField(label=(u'Children age'), min_value=2, max_value=10, initial=2, required=False
That's how i realize formset and validation in views.py:
class BookingForm(View):
template_name = 'booking/booking.html'
def get(self, request, *args, **kwargs):
TouristsFormSet = formset_factory(TouristsForm, extra = 1, max_num = 15)
ChildrenAgeFormSet = formset_factory(ChildrenAgeForm, extra = 1, max_num = 20)
booking_form = HotelForm(prefix='booking_form')
tourists_formset = TouristsFormSet(prefix='tourists')
childrenage_formset = ChildrenAgeFormSet(prefix='childrenage')
return render(request, self.template_name, { 'booking_form' : booking_form, 'tourists_formset' : tourists_formset, 'childrenage_formset' : childrenage_formset })
def post(self, request, *args, **kwargs):
TouristsFormSet = formset_factory(TouristsForm, extra = 1, max_num = 15)
ChildrenAgeFormSet = formset_factory(ChildrenAgeForm, extra = 1, max_num = 20)
booking_form = HotelForm(request.POST, prefix='booking_form')
tourists_formset = TouristsFormSet(request.POST, prefix='tourists')
childrenage_formset = ChildrenAgeFormSet(request.POST, prefix='childrenage')
if booking_form.is_valid() and tourists_formset.is_valid() and childrenage_formset.is_valid():
I add new formset fields in the form using java-script:
$(function(){
$('#id_booking_form-rooms').on('change', function(e){
var n = $('#id_booking_form-rooms').val() || 0;
var html = "";
for (var i = 0; i < n; i++) {
html += "<div>People in the room " + (i + 1) + "</div>"
+ "<br/><label for='id_tourists-" + i + "-adult'>Adults:</label>"
+ "<input id='id_tourists-" + i + "-adult' type='number' name='tourists-" + i + "-adult'/>"
+ "<label for='id_tourists-" + i + "-children'>Children:</label>"
+ "<input id='id_tourists-" + i + "-children' type='number' name='tourists-" + i + "-children' class='children_age'/>"
+ "<div class='extrafieldWrapperChAge'></div>";
}
$(".extrafieldWrapper").html(html);
});
$(".extrafieldWrapper").on('change', '.children_age', function(e){
var n = $(this).val() || 0;
var html = "";
for (var i = 0; i < n; i++) {
html += "<br/><label for='id_childrenage-" + i + "-children_age'>Children age "+(i+1)+"</label>"
+ "<input id='id_childrenage-" + i + "-children_age' type='number' name='childrenage-" + i + "children_age' />";
}
$(this).next('.extrafieldWrapperChAge').html(html);
});
});
There is how look like my template:
<div class="row">
<div class="fieldWrapper">
{% if booking_form.rooms.errors %}
<ol style="list-style-type:square" >
{% for error in booking_form.rooms.errors %}
<li><strong>This field required</strong></li>
{% endfor %}
</ol>
{% endif %}
{{ booking_form.rooms.label_tag }}
{{ booking_form.rooms }}
</div>
<div class="extrafieldWrapper">
{{ tourists_formset.management_form }}
{{ childrenage_formset.management_form }}
</div>
</div>
There is how look like my form in browser:
<div class="fieldWrapper">
<label for="id_booking_form-rooms">Rooms:</label>
<input id="id_booking_form-rooms" type="number" name="booking_form-rooms" min="1">
</div>
<div class="extrafieldWrapper">
<div>People in the room 1</div>
<br>
<label for="id_tourists-0-adult">Adults:</label>
<input id="id_tourists-0-adult" type="number" name="tourists-0-adult">
<label for="id_tourists-0-children">Children:</label>
<input id="id_tourists-0-children" class="children_age" type="number" name="tourists-0-children">
<div class="extrafieldWrapperChAge">
<br>
<label for="id_childrenage-0-children_age">Children age 1</label>
<input id="id_childrenage-0-children_age" type="number" name="childrenage-0children_age">
</div>
</div>
But when i press submit button i always got [u'ManagementForm data is missing or has been tampered with']. What did i wrong? Thanks for your help
When you change the number of your forms in formset on the client side, you should change the ManagementForm hidden fields: form-TOTAL_FORMS, form-INITIAL_FORMS and form-MAX_NUM_FORMS.