Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django automatically set foreign key in form (with class based views)

I want to use a form to generate a new object (say a Book) from a Person's page such that the new Book is automatically associated with that Person via a foreign key, but I am running into trouble getting the Person correctly associated and saved with the form. For my models, I have:

class Person(models.Model):
    p_id = models.PositiveIntegerField(primary_key=True, unique=True)

class Book(models.Model):
    person = models.ForeignKey(Person)
    title = models.CharField(max_length=100)

I then have a custom form to create a Book:

class AddBookForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = ('title', 'person',)
        widgets = {
            'person': forms.HiddenInput,
        }

And a view to create the Book (which is also given the pk (p_id) of the Person):

class AddBook(CreateView):
    model = Book

I have tried various things to get this to work:

  • Pre-populating the Person field with get_initial, but this disappears for some reason with the input is set to hidden (frustratingly).
  • modifying the form_valid method in the view, but this only occurs after the form has already been validated, so I need to add Person before that.
  • modifying the clean_person method in the form class, but that only occurs after the form has been validated by the clean method.

Currently, I am trying to override the clean method. However, I don't know how to get the Person at this point, after the form has already been sent for cleaning. In the view, I could access it with Patient.objects.get(p_id=self.kwargs.get('pk')).

Is there some way I can add the data to the form in my view (as a class-based view) that it won't get stripped away OR is there some way I can access the Person or p_id foreign key at this point to add the data in the clean method?

like image 533
Julia Ebert Avatar asked Dec 11 '22 04:12

Julia Ebert


1 Answers

You're going at it the wrong way: the person is not user input, so this information should not reside in the form. You can override the form_valid method as follows:

class AddBook(CreateView):
    model = Book

    def form_valid(self, form):
        form.instance.person_id = self.kwargs.get('pk')
        return super(AddBook, self).form_valid(form)

This will set the person_id attribute on the instance used by the form to save the data, and then call the super method to save that instance and return a redirect.

like image 101
knbk Avatar answered Dec 22 '22 16:12

knbk