How do I pass a parent id as an fk to child object's ModelForm using generic class-based views in Django?

半腔热情 提交于 2019-11-29 12:43:11

With the url that you defined in author_detail.html the author_id variable will be accessible in the view as self.kwargs['author_id']

# views.py
class BookCreate(CreateView):
...
def form_valid(self, form):
    book = form.save(commit=False)
    author_id = form.data['author_id']
    author = get_object_or_404(Author, id=author_id)
    book.author = author
    return super(BookCreate, self).form_valid(form)
...
def get_context_data(self, **kwargs):
    context = super(BookCreate, self).get_context_data(**kwargs)
    context['a_id'] = self.kwargs['author_id']
    return context

Then in your form you can add:

class BookForm(forms.Modelform):
    ...
    def __init__(self, *args, **kwargs):
        self.fields["author_id"] = forms.CharField(widget=forms.HiddenInput())
        super(BookForm, self).__init__(self, *args, **kwargs)

Then in the template:

  <input type=hidden name="author_id" value="{{ a_id }}">

The form_valid in the view should retrieve the id, get the appropriate author and set that author as the books author. The commit=False prevents the model getting saved at first while you set the author and calling super will result in form.save(commit=True) being called.

You could pass the author id to the form, here's some directions:

class BookForm(forms.Modelform):
    author = None

    class Meta:
        model = Book

    def __init__(self, *args, **kwargs):
        self.author = kwargs.pop('author')
        super(BookForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        # your custom save (returns book)


class BookCreate(CreateView):
    form_class = BookForm

    def get_form_kwargs(self):
        kwargs = super(BookCreate, self).get_form_kwargs()
        kwargs['author'] = # pass your author object

        return kwargs
Adal H. Vega

I had a similar situation and, when doing the accepted answer steps I encountered 2 errors (I'm using Python 2.7):

  1. object has no attribute 'fields' which was fixed by using answer to a similar question: https://stackoverflow.com/a/8928501/2097023 from @scotchandsoda:

...self.fields should be placed before calling super(...)

def __init__(self, users_list, **kw):
    super(BaseWriteForm, self).__init__(**kw)
    self.fields['recipients'].queryset = User.objects.filter(pk__in=users_list)
  1. object has no attribute 'get' which was fixed using answer: https://stackoverflow.com/a/36951830/2097023 from @luke_dupin:

...this error can also be generated by incorrectly passing arguments in the init of a form, which is used for an admin model.

Example:

class MyForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(self, *args, **kwargs)

Notice the double passing of self? It should be:

class MyForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!