Django forms | Passing "value" widget attribute.

Morning all

So I have a Django form which work and submits the form data to my third party CRM as expected.

However, this form allows browsers to send feedback about the page with which the form is placed on.

Because of this, I have a hidden field (HiddenInput(...)) which passes the URL of the current page in the value attribute so we know which page the user is referring to. The URL is then to be seen on our end as part of the message body.

This is how I have the value widget set up.

File name: legal.forms.py

    url   =   forms.CharField(widget=forms.HiddenInput(attrs={'value' : '{{urll}}'}))  

This is the equivalent of:

<input type = "hidden" value="<insert value>"..../>

the url context variable is attained by the following function:

Filename ‘legal.context_processors.py’

def legal__url_path (request):
    url = request.get_host() + request.path 
    return {'url':url}

This function has been declared in the list of context processors in the settings.py in the following fashion:

'OPTIONS': {
            'context_processors': [
                .....
                .....
                .....
                'legal.context_processors.legal__url_path',
                .....
                .....
                .....
            ],

I have read the official documentation which can be found hereThe Forms API & I have to say, it’s as clear as mud.

I don’t understand why the following correctly passes the url in the ‘value’ attribute, as follows:

‘’

With the result being:

However, doing it this way:

`…widget=forms.HiddenInput(attrs={‘value’ : ‘{{urll}}’})…’

returns the literal string, like this?

Screenshot 2024-02-12 122710

To summarise

The in the image below, the top input is constructed via Django, the bottom is achieved via the standard HTML methodology:

value-attr

What am I missing here exactly?

Thank you.

Because this:
url = forms.CharField(widget=forms.HiddenInput(attrs={'value' : '{{urll}}'}))

Defines a literal value to be used as an attribute for that field. The attrs dict contains values that are interpolated into the template being rendered, the value itself is not interpreted during the rendering process.

To dynamically set values for fields in a form, you pass the values to the form constructor using the initial parameter in the view where the form is being used. See the docs and examples for Initial form values.

Now, if you’re setting this in a context processor because you’re doing this in multiple locations, then you’re likely going to want to render that directly as a separate template. The context processor is functioning at a separate point in time from when the form is being processed.

You may need to render that tag manually within your form and not as part of the Django form.

For example:

<form>
  {{ my_form}}
  {% include 'url_field.html' %}
</form>

Where URL field is your template that renders what the context processor adds to the context.

[Edit: This also implies that either: You don’t have url as a form field - which means you would need to explicitly pull that from the POST data in the view that processes the field, or you render all-but-this-field manually so that this field doesn’t get rendered twice. But my actual recommendation would depend upon how many different forms you’re needing to do this with. If it’s only one or two, I would suggest removing the context processor and doing it within the view.]

Great, I’m just going to include this as a separate field using the HTML methodology., in the following fashion:

<form method="POST"> 
            {% csrf_token %}

            {% for hidden in form.hidden_fields %}
            {{ hidden }}
            {% endfor %}

            {% for field in form.visible_fields %}
            <div class="form-group">
                {{ field.errors }}
                <label>{{ field.label_tag }}</label>
                <p>{{ field }}</p>
            </div>
            {% endfor %}
            <div class="disclaimer">
                {% include 'snippets/privacy-notice.html' %}
            </div>
            <input type="hidden" name="url" value="{{url}}"/>
            <button type="submit" class="btn btn--pink">Submit Feedback</button>
        </form>

I work on the It’ll either be easy or it’s not happening principle. Django just complicates this more than it needs to be IMHO, & I can’t deal with it right now.

Whoever writes this documentation just seems to assume we’re all experts in Django.

Thank you for your time.

On a personal note, how have I come across this time around? Better? Worse? Calm? :slight_smile:

(Not sarcasm :blush:)