How can I build a context for the render function

hello,

I am still working hard to learn about Django :slight_smile:
I would like to build a dict or an object to return datas to a template.

For that I am using the render function
return render(request, 'map/station.html', {'stations': d, 'sensors': sensors, 'fields_list': fields_list, 'stations_list': stations_list})

I am actually working on the d variable (I will give a better name later)
my goal is to have a similar structure as the following

{
  "station_name":"st-1",
  "station_longname":"Station 1",
  "collectionid": 1524,
  "date":"2022-07-16 20:00:002",
  "sondes":{
    "Temp":26,
    "Pressure": 40 ,
    "humidity":60,
  },
}

i would like to have some clarification:
Do I need a dict or a an object?
And it would be very helpfully if you can give me an exemple of how to prepare it to pass in my render function

Here is a draft of what I tried to start without success

def station(request, idstation, idfield):

    """
    class St():
        def __init__(self, station_name, station_longname):
            self.station_name = station_name
            self.station_longname = station_longname

        def addStationname(self, stationname):
           self.station_name += stationname
        
        stations_and_sensors = St("name","longname")
    """

    d = {"station_name": "toto", "station_longname": "longname"}

    for e in Sensors.objects.filter(stations_id_station=idstation, sensor_active=1):
        print(e.stations_id_station.station_name)
        d['station_name'] = e.stations_id_station.station_name
        print(e.sensor_name)
        for p in Measures.objects.filter(sensors_id_sensor=e.id_sensor).order_by('-measure_created')[:5]:
            print(p.value, p.measure_created)


    print(d)


    return render(request, 'map/station.html', {'stations': d})

Many thankd for your help

I’m not seeing what the issue is that you’re trying to address here.

You seem to have a perfectly good start to it, so I don’t know where you may need assistance.

You wrote:

What is not succeeding here?

Yes, the context you pass to the rendering engine is a dict. (See the docs at Templates | Django documentation | Django)

If you want your data dict to be named d, then you could do something like this:
(adapted from your post)

d = {
  "station_name": "st-1",
  "station_longname": "Station 1",
  "collectionid": 1524,
  "date": "2022-07-16 20:00:002",
  "sondes": {
    "Temp": 26,
    "Pressure": 40 ,
    "humidity": 60,
  },
}

Any of those constant values on the right of the colon can be replaced by a variable. For example, if you have a variable named long_name that contains the name you want placed in the key named station_longname, then instead of "station_longname":"Station 1", you could write "station_longname": long_name.

Dear @KenWhitesell
Thanks a lot for you reply and nice help. That helped me a lot
Then I do not know what I did wrong but I tried again.

To test and learn, I started with he two follow dictionnary

d = {
        'station_name': 'st-1',
        'station_longname': 'Station 1',
        'collectionid': 1524,
        'date': '2022-07-16 20:00:002',
        'sondes': {
            'Temp': 26,
            'Pressure': 40,
            'humidity': 60
        }
    }

    md = {
            1:
            {
                'station_name': 'st-1',
                'station_longname': 'Station 1',
                'collectionid': 1524,
                'date': '2022-07-16 20:00:002',
                'sondes': {
                    'Temp': 26,
                    'Pressure': 40,
                    'humidity': 60
                }
            },
            2:{
                 'station_name': 'st-2',
                 'station_longname': 'Station 2',
                 'collectionid': 1525,
                 'date': '2022-07-16 20:00:002',
                 'sondes': {
                     'Temp': 26,
                     'Pressure': 40,
                     'humidity': 60
                 }
             }
        }

    test = [
        {
            'station_name': 'st-1',
            'station_longname': 'Station 1',
            'collectionid': 1524,
            'DATE': '2022-07-16 20:00:002',
            'sondes': {
                'Temp': '26',
                'Pressure': 40,
                'humidity': 60,
            },
        },
        {
            'station_name': 'st-2',
            'station_longname': 'Station 2',
            'collectionid': 1525,
            'date': '2022-07-16 20:00:002',
            'sondes': {
                'Temp': 26,
                'Pressure': 40,
                'humidity': 60,
            },
        },
    ]

The last test was successfull. but it look like a json string, isn’t?

I passed test here
return render(request, 'map/station.html', {'stations': test})
and in my gabarit, I could get the station_name, station_longname.

Thanks.

Now I am going to try to build the test with the value coming from my database by adding element

In fact, it would be nice if I can have some help.
I spend 3 hours trying to do it.
I got something nice but not enough :slight_smile:

I created a context variable station_sondes = []. For now, it will contains the stations and the associated sensors

Here is my try

    for st in Stations.objects.filter(station_active=1, fields_id_field=idfield):
        print("station_name:", st.station_name)
        print("station_longname:", st.station_longname)
        print("collection_id:", '??')
        print("collation_date", "??")
        print("sensors:")
        station_sondes.append( {
            'station_name': st.station_name,
            'station_longname': st.station_longname,
            'collection_id': '??',
            'collation_date':'??',
            'sondes': {}
        })

        for se in Sensors.objects.filter(stations_id_station=idstation, sensor_active=1):
            print("\tsensor_name:", se.sensor_name)
            print("\tvalues:")
            #station_sondes.sondes = {'ww':'11'}
            station_sondes.sondes.append(
                {
                    'sensors_name': se.sensor_name,
                    'sensors_longname': se.sensor_longname
                 }
            )
            for me in Measures.objects.filter(sensors_id_sensor=se.id_sensor).order_by('-measure_created')[:5]:
                print("\t\t", me.value, me.measure_created)

As you can see, I first query my stations table

for st in Stations.objects.filter(station_active=1, fields_id_field=idfield):
        print("station_name:", st.station_name)
        print("station_longname:", st.station_longname)
        print("collection_id:", '??')
        print("collation_date", "??")
        print("sondes:")
        station_sondes.append( {
            'station_name': st.station_name,
            'station_longname': st.station_longname,
            'collection_id': '??',
            'collation_date':'??',
            'sondes': {}
        })

and I appended the result to station_sondes. That’s works nice.
Nota bene:

  • I used the name sensors in french (sondes) to not confuse with the model Sensors
  • For now, I ignore collection_id and collection_date because I want to collect the sondes (sensors) connected to a station and having a nested contect
  • a collection is a set of measures that a station take in the same time. But I will see that later

Then I query the sensors tables to get all sensors connected to the associate station and I want to have the sensors list to ‘sondes’ key of the dict

    for st in Stations.objects.filter(station_active=1, fields_id_field=idfield):
        print("station_name:", st.station_name)
        print("station_longname:", st.station_longname)
        print("collection_id:", '??')
        print("collation_date", "??")
        print("sensors:")
        station_sondes.append( {
            'station_name': st.station_name,
            'station_longname': st.station_longname,
            'collection_id': '??',
            'collation_date':'??',
            'sondes': {} # []
        })

        for se in Sensors.objects.filter(stations_id_station=idstation, sensor_active=1):
            print("\tsensor_name:", se.sensor_name)
            print("\tvalues:")
            # station_sondes['sondes'] = {'ww':'11'}
            station_sondes.sondes.append( {'ww':'11'})
            #station_sondes.sondes.append(
            #    {
            #        'sensors_name': se.sensor_name,
            #        'sensors_longname': se.sensor_longname
            #     }
            #)

I first tried to append a test element name ww but I got the error

‘list’ object has no attribute ‘sondes’

Then I tried to change this 'sondes': [] # {} without success.

I finally tried to add a element as the following station_sonde[‘sondes’] = {‘ww’:‘11’} without success

I believe that append() is the solution, but I may have missed something.
Someone could lead me to the right direction?

Many thnaks

Your indentation is not correct in this section:

This code as shown is syntactically incorrect and would generate an error. I will assume that the for statement is actually outdented four spaces.

You have:

Which means that station_sondes is a list. It’s not an object, which makes the following invalid:

Generating this error:

If I’m understanding what you’re trying to get to, it would be more clear if you did something like the following:

        a_station_sonde =  {
            'station_name': st.station_name,
            'station_longname': st.station_longname,
            'collection_id': '??',
            'collation_date':'??',
            'sondes': [] # This needs to be a list because you're adding multiple items here
        }

        for se in Sensors.objects.filter(stations_id_station=idstation, sensor_active=1):
            a_station_sonde['sondes'].append({
                'sensors_name': se.sensor_name,
                'sensors_longname': se.sensor_longname
            })

        station_sondes.append(a_station_sonde)

You could also do it like this, but I don’t think it’s as clear:

    for st in Stations.objects.filter(station_active=1, fields_id_field=idfield):
        station_sondes.append( {
            'station_name': st.station_name,
            'station_longname': st.station_longname,
            'collection_id': '??',
            'collation_date':'??',
            'sondes': []   # This needs to be a list because you're adding multiple items here
        })

        for se in Sensors.objects.filter(stations_id_station=idstation, sensor_active=1):
            station_sondes[-1]['sondes'].append(
                {
                    'sensors_name': se.sensor_name,
                    'sensors_longname': se.sensor_longname
                 }
            )

You must, at all times, be aware of the data types you are using and what statements or functions are valid with those types.

Dear @KenWhitesell

Many thanks, It helped me a lot.
I have some issue but I think I have to first to retructure the " menu". Actually, my way does not make sens. Let me clean that.

I have some question more, but let me try first before asking and re-organise my way to display that “menu”

many thank, I come back to keep you informed of the result

So I am already back :slight_smile:

I adapted my view and now I successful did that

def field(request, idfield):
    """Return the active station according to a selected field."""
    fields_list = Fields.objects.filter(field_active=1)
    #stations_list = Stations.objects.filter(fields_id_field=idfield, station_active=1)

    stations_list = []
    for st in Stations.objects.filter(fields_id_field=idfield, station_active=1):
        print("station_name:", st.station_name)
        print("station_longname:", st.station_longname)
        print("collection_id:", '??')
        print("collation_date", "??")
        print("sondes:")

        a_stationsonde = {
            'id_station': st.id_station,
            'station_name': st.station_name,
            'station_longname': st.station_longname,
            'collection_id': '??',
            'collation_date': '??',
            'sondes': [],
        }

        for se in Sensors.objects.filter(stations_id_station=st.id_station, sensor_active=1):
            print("\tsensor_name:", se.sensor_name)
            print("\tvalues:")
            # station_sondes.sondes.append({'ww':'11'})
            a_stationsonde['sondes'].append({
                'sensors_name': se.sensor_name,
                'sensors_longname': se.sensor_longname
            })


        stations_list.append(a_stationsonde)

        #print(i)
        #i = i + 1
    #s_json = json.dumps(stations_list, indent=4)
    #return HttpResponse(s_json, content_type='application/json')
    return render(request, 'map/field.html', {'stations_list': stations_list, 'fields_list': fields_list})

Now, I am back to my template and I could print all my stations according to a field

    {% if stations_list %}
        <h4>Stations</h4>
        <ul>
            {% for station in stations_list %}
            <li>
                {{ station.id_station }} ({{ station.station_longname }}
            </li>
            {% endfor %}
        </ul>

    {% else %}
        <p>No Station available.</p>
    {% endif %}

But I would like to have the sensors belonging to a station and bellow a station

The following does not work and I explain what

    {% if stations_list %}
        <h4>Stations</h4>
        <ul>
            {% for station in stations_list %}
            <li>
                {{ station.id_station }} ({{ station.station_longname }} {{ station.sondes }}
                <ul>
                    {% for x in stations.sondes  %}
                    <li>{{ x }}</li>
                    {% empty %}
                    <li>empty</li>
                    {% endfor %}
                </ul>
            </li>
            {% endfor %}
        </ul>

    {% else %}
        <p>No Station available.</p>
    {% endif %}

First this {{ station.sondes }} print this

[{‘sensors_name’: ‘te’, ‘sensors_longname’: ‘Temp. Air’}, {‘sensors_name’: ‘pr’, ‘sensors_longname’: ‘Pression’}, {‘sensors_name’: ‘hu’, ‘sensors_longname’: ‘Humidité’}, {‘sensors_name’: ‘ba’, ‘sensors_longname’: ‘Batterie’}, {‘sensors_name’: ‘su’, ‘sensors_longname’: ‘Radiation solaire’}, {‘sensors_name’: ‘wd’, ‘sensors_longname’: ‘Direction du vent’}, {‘sensors_name’: ‘an’, ‘sensors_longname’: ‘Vitesse du vent’}, {‘sensors_name’: ‘ga’, ‘sensors_longname’: ‘Gauge’}]

then I would like to loop it to print the value of sensors_name and sensors_longname
but I guess I did it wrong because it alway print empty

I guess this part is wrong

{% for x in stations.sondes  %}

I tried

{% for x in {{ stations.sondes}}  %}

without success.

Then I wonder how can I loop a template tag. May be, there is a syntax that I ignore. Browsing with google does help, sadly

Many thanks

You have:

which creates a local variable named station that you can access in your template.

Then you have:

Which references something that doesn’t exist. (You have stations here instead of station, which is what you defined in the outer loop.)

Ok, so stupid, I am.
Of course, this works now

{% if stations_list %}
        <h4>Stations</h4>
        <ul>
            {% for station in stations_list %}
            <li>
                {{ station.id_station }} ({{ station.station_longname }} ({{ station.sondes|length }})
                <ul>
                    {% for se in station.sondes  %}
                    <li>{{ se.sensor_name }} {{ se.sensor_longname }}</li>
                    {% empty %}
                    <li>empty</li>
                    {% endfor %}
                </ul>
            </li>
            {% endfor %}
        </ul>

    {% else %}
        <p>No Station available.</p>
    {% endif %}

I am very happy of the actual result
Many thanks for your great help and patience. i will continue tomorrow. It’s 2am at my place.