Django CRUD update object with many to one relationship to user

夙愿已清 提交于 2019-12-24 02:25:39

问题


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.


回答1:


After a lot of trial and error I found a solution. I had been using inline formsets because I kept finding answers that pointed that direction, but I would rather do it manually if possible and I had been trying, but how I had been doing this did not work in this instance for some reason.

I had been trying something like:

case = form.save(commit = False)
case.user = request.user

or

form = (request.POST, instance = request.user)
form.save()

I came across this solution and it now works as intended without inline formsets.

form.instance.user = request.user
form.save()

This looks almost equivalent to what I had been doing, but it worked.



来源:https://stackoverflow.com/questions/43671458/django-crud-update-object-with-many-to-one-relationship-to-user

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!