I followed along the awesome tutorial How to Implement CRUD Using Ajax and Json by Vitor Freitas. For my project I have an object with a many to one relationship with the user that I want users to be able to add and update. I can add the object, but when I try to update it throws a
ValueError: Cannot query "Case object": Must be "User" instance.
views.py
def case_update(request, pk):
case = get_object_or_404(Case, pk=pk)
if request.method == 'POST':
form = CaseForm(request.POST, instance=case)
else:
form = CaseForm(instance=case)
return save_case_form(request, form, 'cases/includes/partial_case_update.html')
It breaks when I try to save the edit, but I am struggling to see a way around this. To edit this case, I need the form to be an instance of this particular case as the user may have many cases. When I set the instance to user, nothing happens, when I remove the instance altogether it obviously just makes a copy of the case so I have two of the same cases.
I can post more code if necessary. Thank you
EDIT
I refactored my code using only the inlineformset and it is working... kind of. I now can edit cases, but I still cannot edit a single case. I continue to receive a ValueError: Cannot query "Case object": Must be "User" instance
when I try to do an instance of case = get_object_or_404(Case, pk=pk)
with the inlineformset. When I change this to an instance of user it brings up all the cases of that particular user, but it saves correctly.
def save_case_form(request, case_formset, template_name):
data = dict()
if request.method == 'POST':
if case_formset.is_valid():
case_formset.save()
data['form_is_valid'] = True
cases = Case.objects.all()
data['html_case_list'] = render_to_string('cases/includes/partial_case_list.html', {
'cases': cases
})
else:
data['form_is_valid'] = False
context = {'case_formset' : case_formset}
data['html_form'] = render_to_string(template_name, context, request=request)
return JsonResponse(data)
def case_create(request):
if request.method == 'POST':
case_formset = CaseFormset(request.POST, instance = request.user)
else:
case_formset = CaseFormset()
return save_case_form(request, case_formset, 'cases/includes/partial_case_create.html')
def case_update(request, pk):
case = get_object_or_404(Case, pk=pk)
if request.method == 'POST':
case_formset = CaseFormset(request.POST, instance=request.user)
else:
case_formset = CaseFormset(instance=request.user)
return save_case_form(request, case_formset, 'cases/includes/partial_case_update.html')
forms.py
class CaseForm(forms.ModelForm):
class Meta:
model = Case
fields = ('title', 'publication_date', 'author', 'price', 'pages', 'case_type', )
CaseFormset = inlineformset_factory(User,Case,
fields = ('title', 'publication_date',
'author', 'price',
'pages', 'case_type', ),
can_delete = False,
extra = 1)
EDIT
A non DRY implementation that works:
forms.py
class CaseForm(forms.ModelForm):
class Meta:
model = Case
fields = ('title', 'publication_date', 'author', 'price', 'pages', 'case_type', )
CaseFormset = inlineformset_factory(User,Case,
fields = ('title', 'publication_date',
'author', 'price',
'pages', 'case_type', ),
can_delete = False,
extra = 1)
CaseFormsetUpdate = inlineformset_factory(User,Case,
fields = ('title', 'publication_date',
'author', 'price',
'pages', 'case_type', ),
can_delete = False,
extra = 0)
views.py
def save_case_form(request, case_formset, template_name):
data = dict()
if request.method == 'POST':
if case_formset.is_valid():
case_formset.save()
data['form_is_valid'] = True
cases = Case.objects.all()
data['html_case_list'] = render_to_string('cases/includes/partial_case_list.html', {
'cases': cases
})
else:
data['form_is_valid'] = False
context = {'case_formset' : case_formset}
data['html_form'] = render_to_string(template_name, context, request=request)
return JsonResponse(data)
def case_create(request):
if request.method == 'POST':
case_formset = CaseFormset(request.POST, instance = request.user)
else:
case_formset = CaseFormset()
return save_case_form(request, case_formset, 'cases/includes/partial_case_create.html')
def case_update(request, pk):
case = get_object_or_404(Case, pk=pk)
if request.method == 'POST':
case_formset = CaseFormsetUpdate(request.POST, instance=request.user)
else:
case_formset = CaseFormsetUpdate(instance=request.user, queryset = Case.objects.filter(pk=pk))
return save_case_form(request, case_formset, 'cases/includes/partial_case_update.html')
I was unable to find a way to change the extra parameter on an inline formset when it is instantiated in views. So I just made a second one with extra set to 0 and added that to my update case view. I would still be interested in a better approach.