我的formset有一个奇怪的问题。
当我添加或更新现有模型时,所有工作都完美,但当我检查模板中的单选按钮删除并保存时我有这个错误----->>>>:
TypeError at /pro/edit/carted/ncavl189kabp97/hozegyc3f93ehb9ana/
'NoneType' object is not callable
Request Method: POST
Request URL: http://localhost:8000/pro/edit/carted/ncavl189kabp97/hozegyc3f93ehb9ana/
Django Version: 1.8.3
Exception Type: TypeError
Exception Value:
'NoneType' object is not callable
Exception Location: C:\Python34\lib\site-packages\django\forms\models.py in save_existing_objects, line 754
Python Executable: C:\Python34\python.exe
Python Version: 3.4.3
这是我的view.py
def edit_carted(request, place_code, det_seq):
template_name = 'mealandscoreappmanager/edit_carted.html'
args = {}
args.update(csrf(request))
get_mealplace = get_place_by_code(place_code)
# On recupère le carted correspondant au detseq (equivalent id)
carted_by_seq = get_cartdetail_by_seq(det_seq, get_mealplace)
class RequiredFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
meal_extra_form_set = inlineformset_factory(
CarteDetails,
MealExtra,
form=MealExtraForm,
can_delete=True,
extra=1, )
if request.method == 'POST':
form = CardDetailForm(
request.POST, user=request.user, instance=carted_by_seq)
extra_form_set = meal_extra_form_set(
request.POST, request.FILES, instance=carted_by_seq)
if form.is_valid() and extra_form_set.is_valid():
form.save()
extra_form_set.save()
messages.success(request, DEFAULTMSG)
return HttpResponseRedirect(
reverse(
'manage-core:core-list-cartdetail',
args=(get_mealplace.code, ),
current_app=request.resolver_match.namespace,
)
)
else:
if get_mealplace.partner.account_user.has_perm(
'mealandscoreappmanager.pro_account_manage_{0}'.format(
request.user.profile.mealplace.code)
) is False:
raise PermissionDenied
# On genere le dictionnaire de données
carted_data = get_initial_cartd_data(carted_by_seq)
# On génère un formulaire simple correspondant au data dict
form = CardDetailForm(
initial=carted_data,
user=request.user,
)
extra_form_set = meal_extra_form_set(instance=carted_by_seq)
args['item_id'] = det_seq
args['formset'] = extra_form_set
args['form'] = form
args['partner'] = get_mealplace
return render_to_response(
template_name,
args,
context_instance=RequestContext(request)
)
def edit_carted(request, place_code, det_seq):
template_name = 'mealandscoreappmanager/edit_carted.html'
args = {}
args.update(csrf(request))
get_mealplace = get_place_by_code(place_code)
# On recupère le carted correspondant au detseq (equivalent id)
carted_by_seq = get_cartdetail_by_seq(det_seq, get_mealplace)
class RequiredFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
meal_extra_form_set = inlineformset_factory(
CarteDetails,
MealExtra,
form=MealExtraForm,
can_delete=True,
extra=1, )
if request.method == 'POST':
form = CardDetailForm(
request.POST, user=request.user, instance=carted_by_seq)
extra_form_set = meal_extra_form_set(
request.POST, request.FILES, instance=carted_by_seq)
if form.is_valid() and extra_form_set.is_valid():
form.save()
extra_form_set.save()
messages.success(request, DEFAULTMSG)
return HttpResponseRedirect(
reverse(
'manage-core:core-list-cartdetail',
args=(get_mealplace.code, ),
current_app=request.resolver_match.namespace,
)
)
else:
if get_mealplace.partner.account_user.has_perm(
'mealandscoreappmanager.pro_account_manage_{0}'.format(
request.user.profile.mealplace.code)
) is False:
raise PermissionDenied
# On genere le dictionnaire de données
carted_data = get_initial_cartd_data(carted_by_seq)
# On génère un formulaire simple correspondant au data dict
form = CardDetailForm(
initial=carted_data,
user=request.user,
)
extra_form_set = meal_extra_form_set(instance=carted_by_seq)
args['item_id'] = det_seq
args['formset'] = extra_form_set
args['form'] = form
args['partner'] = get_mealplace
return render_to_response(
template_name,
args,
context_instance=RequestContext(request)
)
这是我的formset.js代码
那是我的模板
$(document).ready(function () {
// Code adapted from http://djangosnippets.org/snippets/1389/
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 deleteForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (formCount > 1) {
// Delete the item/form
$(btn).parents('.item').remove();
var forms = $('.item'); // Get all the forms
// Update the total number of forms (1 less than before)
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
var i = 0;
// Go through the forms and set their indices, names and IDs
for (formCount = forms.length; i < formCount; i++) {
$(forms.get(i)).children().children().each(function () {
if ($(this).attr('type') == 'text') updateElementIndex(this, prefix, i);
});
}
} // End if
else {
alert("Il faut au moins un supplement");
}
return false;
}
function addForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
// You can only submit a maximum of 10 todo items
if (formCount < 10) {
// Clone a form (without event handlers) from the first form
var row = $(".item:first").clone(false).get(0);
// Insert it after the last form
$(row).removeAttr('id').hide().insertAfter(".item:last").slideDown(300);
// Remove the bits we don't want in the new row/form
// e.g. error messages
$(".errorlist", row).remove();
$(row).children().removeClass("error");
// Relabel or rename all the relevant bits
$(row).children().children().each(function () {
updateElementIndex(this, prefix, formCount);
$(this).val("");
});
// Add an event handler for the delete item/form link
$(row).find(".delete").click(function () {
return deleteForm(this, prefix);
});
// Update the total form count
$("#id_" + prefix + "-TOTAL_FORMS").val(formCount + 1);
} // End if
else {
alert("Sorry, you can only enter a maximum of ten items.");
}
return false;
}
// Register the click event handlers
$("#add").click(function () {
return addForm(this, "mealextra_set");
});
$(".delete").click(function () {
return deleteForm(this, "mealextra_set");
});
});
$(document).ready(function () {
// Code adapted from http://djangosnippets.org/snippets/1389/
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 deleteForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (formCount > 1) {
// Delete the item/form
$(btn).parents('.item').remove();
var forms = $('.item'); // Get all the forms
// Update the total number of forms (1 less than before)
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
var i = 0;
// Go through the forms and set their indices, names and IDs
for (formCount = forms.length; i < formCount; i++) {
$(forms.get(i)).children().children().each(function () {
if ($(this).attr('type') == 'text') updateElementIndex(this, prefix, i);
});
}
} // End if
else {
alert("Il faut au moins un supplement");
}
return false;
}
function addForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
// You can only submit a maximum of 10 todo items
if (formCount < 10) {
// Clone a form (without event handlers) from the first form
var row = $(".item:first").clone(false).get(0);
// Insert it after the last form
$(row).removeAttr('id').hide().insertAfter(".item:last").slideDown(300);
// Remove the bits we don't want in the new row/form
// e.g. error messages
$(".errorlist", row).remove();
$(row).children().removeClass("error");
// Relabel or rename all the relevant bits
$(row).children().children().each(function () {
updateElementIndex(this, prefix, formCount);
$(this).val("");
});
// Add an event handler for the delete item/form link
$(row).find(".delete").click(function () {
return deleteForm(this, prefix);
});
// Update the total form count
$("#id_" + prefix + "-TOTAL_FORMS").val(formCount + 1);
} // End if
else {
alert("Sorry, you can only enter a maximum of ten items.");
}
return false;
}
// Register the click event handlers
$("#add").click(function () {
return addForm(this, "mealextra_set");
});
$(".delete").click(function () {
return deleteForm(this, "mealextra_set");
});
});
那是我的model.py部分:
<div class="row">
<div class="col-md-12">
<form role="form form-horizontal" method="POST" action="" class="form-horizontal" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<div class="col-md-12">
<div class="panel panel-primary">
<div class="panel-heading">{% trans "Définir menu" %}</div>
<div class="panel-body">
{% bootstrap_form form %}
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<div class="mealands-mmeal-content">
<div class="mmeal-content-heading">{% trans "Accompagnement (ou supplements)" %} <span class="pull-right"><a href="#" id="add" class="btn btn-primary"><i class="fa fa-plus-circle"></i> {% trans "Ajouter supplément" %}</a></span></div>
<p class="help-block">
</p>
<div class="mmeal-content-body">
{{ formset.management_form }}
<div class="row">
{% for forms in formset %}
{{forms.id}}
<div class="col-md-4 item">
<div lass="form-group">
<label class="control-label" for="{{forms.name.id_for_label}}">
{{forms.name.label}}
{% if forms.name.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
{{forms.name}}
<div class="input-error-container">
{{ forms.name.errors }}
</div>
</div>
<div lass="form-group">
<label class="control-label" for="{{forms.taxe.id_for_label}}">
{{forms.taxe.label}}
{% if forms.taxe.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
{{forms.taxe}}
<div class="input-error-container">
{{ forms.taxe.errors }}
</div>
</div>
<div lass="form-group">
<label class="control-label" for="{{forms.dispo.id_for_label}}">
{{forms.dispo}}
{% trans "Disponible ?" %}
{% if forms.dispo.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
</div>
{% if formset.can_delete %}
{{forms.id}}
<div lass="form-group">
<label class="control-label" for="{{forms.DELETE.id_for_label}}">
{{forms.DELETE}}
{{forms.DELETE.label}}
{% if forms.DELETE.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
</div>
{% endif %}
<a href="#" class="delete btn btn-danger"><i class="fa fa-times-circle"></i> {% trans "Supprimer supplément" %}</a>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% buttons %}
<button type="submit" class="btn btn-default" name="save_and_add_another">
<i class="fa fa-retweet"></i> {% trans "Enregistrer et ajouter nouveau" %}
</button>
<button type="submit" class="btn btn-primary" name="save">
<i class="fa fa-check-square-o"></i> {% trans "Enregistrer" %}
</button>
{% if item_id %}
<a href="{% url "manage-core:core-delete-cartdetail" partner.code item_id %}" class="btn btn-danger"><i class="fa fa-times-circle"></i> {% trans "Supprimer" %}</a>
{% endif %}
{% endbuttons %}
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form role="form form-horizontal" method="POST" action="" class="form-horizontal" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<div class="col-md-12">
<div class="panel panel-primary">
<div class="panel-heading">{% trans "Définir menu" %}</div>
<div class="panel-body">
{% bootstrap_form form %}
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<div class="mealands-mmeal-content">
<div class="mmeal-content-heading">{% trans "Accompagnement (ou supplements)" %} <span class="pull-right"><a href="#" id="add" class="btn btn-primary"><i class="fa fa-plus-circle"></i> {% trans "Ajouter supplément" %}</a></span></div>
<p class="help-block">
</p>
<div class="mmeal-content-body">
{{ formset.management_form }}
<div class="row">
{% for forms in formset %}
{{forms.id}}
<div class="col-md-4 item">
<div lass="form-group">
<label class="control-label" for="{{forms.name.id_for_label}}">
{{forms.name.label}}
{% if forms.name.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
{{forms.name}}
<div class="input-error-container">
{{ forms.name.errors }}
</div>
</div>
<div lass="form-group">
<label class="control-label" for="{{forms.taxe.id_for_label}}">
{{forms.taxe.label}}
{% if forms.taxe.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
{{forms.taxe}}
<div class="input-error-container">
{{ forms.taxe.errors }}
</div>
</div>
<div lass="form-group">
<label class="control-label" for="{{forms.dispo.id_for_label}}">
{{forms.dispo}}
{% trans "Disponible ?" %}
{% if forms.dispo.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
</div>
{% if formset.can_delete %}
{{forms.id}}
<div lass="form-group">
<label class="control-label" for="{{forms.DELETE.id_for_label}}">
{{forms.DELETE}}
{{forms.DELETE.label}}
{% if forms.DELETE.field.required %}
<span class="special_class">*</span>
{% endif %}
</label>
</div>
{% endif %}
<a href="#" class="delete btn btn-danger"><i class="fa fa-times-circle"></i> {% trans "Supprimer supplément" %}</a>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% buttons %}
<button type="submit" class="btn btn-default" name="save_and_add_another">
<i class="fa fa-retweet"></i> {% trans "Enregistrer et ajouter nouveau" %}
</button>
<button type="submit" class="btn btn-primary" name="save">
<i class="fa fa-check-square-o"></i> {% trans "Enregistrer" %}
</button>
{% if item_id %}
<a href="{% url "manage-core:core-delete-cartdetail" partner.code item_id %}" class="btn btn-danger"><i class="fa fa-times-circle"></i> {% trans "Supprimer" %}</a>
{% endif %}
{% endbuttons %}
</form>
</div>
</div>
现在,当我编辑现有的模型时,这一切都有效!
但当我检查删除({{form.delete}})时,我收到错误:&#39; NoneType&#39;对象不可调用
我检查了我的错误页面并看到了这条消息!
class CarteDetails(models.Model):
PERIOD_DAY = (
(MORNING, _('Matin')),
(NOON, _('Midi')),
(AFTERNOON, _('Après midi')),
(EVENING, _('Soir')),
)
**Note that sequence is my primary key**
sequence = models.CharField(max_length=25, primary_key=True)
jour = models.CharField(
_('Jour'), max_length=1, choices=DAYSLIST)
period = models.CharField(
_('Période de la journée'),
max_length=1, choices=PERIOD_DAY, default=MORNING)
date_add = models.DateTimeField(auto_now_add=True)
meal = models.ForeignKey(
Meal, verbose_name=_('Plat'), null=True)
# We add s because in view we'll use formset
format = models.ForeignKey(Format, verbose_name=_('Format'), null=True)
price = models.DecimalField(
_('Prix'),
max_digits=8,
decimal_places=2,
db_index=True,
null=True,
)
dispo = models.BooleanField(default=True)
existed = models.BooleanField(default=True)
def __str__(self):
return '%s - %s - %s' % (
self.get_jour_display(),
self.mealformat, self.get_period_display())
class Meta:
ordering = ['sequence']
class MealExtra(models.Model):
name = models.CharField(max_length=30)
taxe = models.DecimalField(
_('Taxe'),
max_digits=8,
decimal_places=2,
db_index=True,
)
carted = models.ForeignKey(CarteDetails, null=True)
formule = models.ForeignKey(MealFormat, null=True)
dispo = models.BooleanField(default=True)
existed = models.BooleanField(default=True)
class CarteDetails(models.Model):
PERIOD_DAY = (
(MORNING, _('Matin')),
(NOON, _('Midi')),
(AFTERNOON, _('Après midi')),
(EVENING, _('Soir')),
)
**Note that sequence is my primary key**
sequence = models.CharField(max_length=25, primary_key=True)
jour = models.CharField(
_('Jour'), max_length=1, choices=DAYSLIST)
period = models.CharField(
_('Période de la journée'),
max_length=1, choices=PERIOD_DAY, default=MORNING)
date_add = models.DateTimeField(auto_now_add=True)
meal = models.ForeignKey(
Meal, verbose_name=_('Plat'), null=True)
# We add s because in view we'll use formset
format = models.ForeignKey(Format, verbose_name=_('Format'), null=True)
price = models.DecimalField(
_('Prix'),
max_digits=8,
decimal_places=2,
db_index=True,
null=True,
)
dispo = models.BooleanField(default=True)
existed = models.BooleanField(default=True)
def __str__(self):
return '%s - %s - %s' % (
self.get_jour_display(),
self.mealformat, self.get_period_display())
class Meta:
ordering = ['sequence']
class MealExtra(models.Model):
name = models.CharField(max_length=30)
taxe = models.DecimalField(
_('Taxe'),
max_digits=8,
decimal_places=2,
db_index=True,
)
carted = models.ForeignKey(CarteDetails, null=True)
formule = models.ForeignKey(MealFormat, null=True)
dispo = models.BooleanField(default=True)
existed = models.BooleanField(default=True)
请我帮忙!
谢谢rakwen