Use PK in Django Custom forms safely
If for some reason you aren’t using a ModelForm directly but you need to create a Django form and include a model instance primary key in it to later processing it at a POST request, then you need to make sure it can’t be edited.
Short answer: Use forms.fields.Field.disabled.
Using the PK in a form
Suppose you have a form where you get a model instance passed as a
sentence_main) and in its init initalize a new form field:
from django import forms class SentenceForm(forms.Form): """Used in full *correction*, and in single sentence *edit* """ def __init__(self, *args, **kwargs): """Generate a field for each text's sentence""" sentence_main = kwargs.pop('sentence_main') super().__init__(*args, **kwargs) self.fields["sentencemain"] = forms.CharField( required=False, label=sentence_main.display(), initial=sentence_main.display(), #"initiallll", #unit.literal_translation(text_l1), )
Hidden PK field form
To also have the primary key of this model instance in the form, we include it using a hidden field, with the forms.HiddenInput widget.
HiddenInput field is a special
Input class with
input_type = 'hidden'.
input elements of type "hidden" let web developers include data that cannot be seen or modified by users when a form is submitted. For example, the ID of the content that is currently being ordered or edited, or a unique security token. Hidden inputs are completely invisible in the rendered page, and there is no way to make it visible in the page's content.
Then in our
class SentenceForm(forms.Form): """Used in full *correction*, and in single sentence *edit* """ def __init__(self, *args, **kwargs): ... #build the fields self.fields["sentencemain_pk"] = forms.IntegerField( ... widget=forms.HiddenInput() )
Avoid PK edit in POST
Finally to avoid Web Parameter Tampering, we make sure the primary key can’t be modified in a POST request.
This is a very important step often omitted in tutorials to include a primary key in a form, allowing malicious users to alter the primary key processed in a POST request.
The Web Parameter Tampering attack is based on the manipulation of parameters exchanged between client and server in order to modify application data, such as user credentials and permissions, price and quantity of products, etc. Usually, this information is stored in cookies, hidden form fields, or URL Query Strings, and is used to increase application functionality and control.
This attack can be performed by a malicious user who wants to exploit the application for their own benefit, or an attacker who wishes to attack a third-person using a Man-in-the-middle attack.
To avoid the user altering this field, we use Django’s disabled argument.
class SentenceForm(forms.Form): """Used in full *correction*, and in single sentence *edit* """ def __init__(self, *args, **kwargs): ... #build the fields self.fields["sentencemain_pk"] = forms.IntegerField( ... disabled = True, #it won’t be editable by users widget=forms.HiddenInput() )
And we can trust in the primary key passed in the form when processing the POST request in a view.
The disabled boolean argument, when set to True, disables a form field using the disabled HTML attribute so that it won’t be editable by users. Even if a user tampers with the field’s value submitted to the server, it will be ignored in favor of the value from the form’s initial data.
- Adding a Cancel button in Django class-based views, editing views and formsJuly 15, 2019
- Using Django Model Primary Key in Custom Forms THE RIGHT WAY
- Django formset handling with class based views, custom errors and validationJuly 4, 2019
- How To Use Bootstrap 4 In Django FormsMay 25, 2018
- Understanding Django FormsApril 30, 2018
- How To Create A Form In DjangoJuly 29, 2016