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

后端 未结 3 969
醉话见心
醉话见心 2020-12-20 07:56

I am trying to use Django Generic Class-Based Views to build a CRUD interface to a two-model database. I have a working CRUD interface to the parent model, and am stuck try

相关标签:
3条回答
  • 2020-12-20 08:18

    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.

    0 讨论(0)
  • 2020-12-20 08:34

    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)
    
    0 讨论(0)
  • 2020-12-20 08:38

    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
    
    0 讨论(0)
提交回复
热议问题