Automatically set ForeignKey field in CreateView

Hi there,

I was wondering if there is a way to automatically set a parent when creating a new instance of an object?

i.e. The field is set automatically and not presented to the user at all (or at least is disabled).

I’ve crudely illustrated an example with two parent instances (e.g. House 1 and House 2). Each has a one-to-many relationship with other model instances (e.g. Books, CDs and DVDs).

When the user presses the ‘Add new CD’ button in the House 1 list view, they are taken to the CD Create View. Here the ‘house’ field would be pre-set to House 1.

I’ve gone back over all the tutorials I’ve done, but can’t see anything that covers this.

Many thanks in advance for any tips or pointers!

PS: My project isn’t actually modelling houses and DVDs, that’s just the easiest way to explain!

Yes, there are a couple ways this can be done. (To some degree, the decision will be based on whether or not you can trust your users not to mess with data in your browser. That’s almost never true for sites open to the general public.)

The simplest, least secure method is to pass the primary key to your create view, where it is included in your form as a hidden field (let’s call it “house”). When they enter the new CD, that house field is submitted in the form along with the rest of the data. -

I call this “least secure”, because someone could alter that value of house using their browser tools, causing the CD to be assigned to a different house. (Since we’re talking about an analogy instead of the real topic, I can’t tell how significant an issue this would be.)

If you want something more secure, then you might want to look at something like putting the actual house id in the user’s session under the name of some semi-randomized value, and passing that name as the hidden value in the form. That way, if the user were to alter that value, it’s highly unlikely they would find another valid name - and if they did, it would have to be a name in their session. (I also recommend using a somewhat-randomly generated name, in case the user has multiple tabs open and is sharing their session among those tabs. This helps keep the work separate between the tabs.)

Now, there may be other, easier ways to do this, but the above is the method we use. (It’s cross-platform in that we can implement this regardless of the language of the system. It’s not specifically a Django-based solution.)

Hope this gives you some ideas to work from.

Ken

1 Like

I agree with Ken that using a hidden field is an available option that has limitations because the data can be modified.

Now for the shameless (but relevant!) bit of self-promotion. I discussed this exact subject on my (most recent as of this writing) Twitch stream. The short version of the solution is that I used a hidden field with a CreateView, then added validation to the form to ensure that the user had permission to set things for the provided ID.

If you want to see the details, I’ve posted the video on my website at https://www.mattlayman.com/building-saas/consistent-onboarding/. Here’s the form that I used: https://github.com/mblayman/homeschool/blob/7258674ec540a15cf36fb302a06dac32a3a00302/homeschool/schools/forms.py#L16

2 Likes

Thanks both to @KenWhitesell and @mblayman. The extra description around different ways of approaching this is really handy to know – this is the first time I’ve implemented such a feature, so I honestly had no idea whether Django had a standard in-built way of handling this or not. None of the tutorials I’ve worked through have covered it in quite the way I needed it to work.

I’ve taken a look through the code and I think I understand what the different components are doing. Eve though I wouldn’t have been able to write that off the top of my head in a million years, using that example I’ve managed to hook everything up and looks like it’s working. Hurahh! I guess (*hope!) that’s how everyone starts out.

Thanks again both,