Django generate bootstrap tabs with for loop

Viewed 221

I have a page in my web app with multiple tables, and rather than have them on separate pages or one long list, I want to use tabs and I need to be able to generate these tabs based on how many objects there are.

I'm pretty certain it's just a problem with the template, but I'll include all the other files just in case.

Here are the models relevant to the problem.

class Exercises(models.Model):
    exercise = models.CharField(max_length=45)
    evolution = models.CharField(max_length=8)
    start_date = models.DateTimeField(blank=True, null=True)
    end_date = models.DateTimeField(blank=True, null=True)
    logo = models.TextField(blank=True, null=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['exercise', 'evolution'], name='exercise_evolution_UNIQUE')
        ]

    def __str__(self):
        return f"Exercise: {self.exercise}\t Evolution: {self.evolution}"


class Units(models.Model):
    uic = models.CharField(max_length=10)
    unit_name = models.CharField(unique=True, max_length=45)
    mcc = models.CharField(max_length=5, blank=True, null=True)
    ruc = models.CharField(max_length=10, blank=True, null=True)
    personnel = models.IntegerField(blank=True, null=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['uic', 'mcc', 'ruc'], name='uic_mcc_ruc_UNIQUE')
        ]

    def __str__(self):
        return f"{self.unit_name}"

    def get_uic(self):
        return f'{self.uic}'

class ExercisePersonnel(models.Model):
    exercise = models.ForeignKey('Exercises', models.CASCADE)
    unit = models.ForeignKey('Units', models.CASCADE)
    location = models.ForeignKey('Locations', models.RESTRICT)
    quantity = models.IntegerField()

    def __str__(self):
        return f'{self.unit}'

class UnitEdl(models.Model):
    unit = models.ForeignKey('Units', models.CASCADE)
    equipment = models.ForeignKey('Equipment', models.CASCADE)
    quantity = models.IntegerField()

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['unit', 'equipment'], name='unit_equipment_UNIQUE')

I have functions that use database objects to create additional data that shows up in the tables

functions.py

def get_class_one_chow(pax=1, meals_per_day=2):
    cases_per_day =  pax * meals_per_day / 12
    pallets = cases_per_day / 48
    short_tons = pallets * 1098 / 2000
    twenty_ft_teus = pallets / 16
    ugrs_pallets = (pax * 2) / 50 / 8
    mres_pallets = pax / 12 / 48
    ugrs_short_tons = (ugrs_pallets * 1071 / 2000) + (mres_pallets * 1098 / 2000)
    ugr_twenty_ft_teus = (ugrs_pallets + mres_pallets) / 16

    return {"cases":round(cases_per_day,1),
            "pallets":round(pallets,1),
            "short_tons":round(short_tons,1),
            "twenty_ft_teus":round(twenty_ft_teus,1),
            "ugrs_pallets":round(ugrs_pallets,1),
            "mres_pallets":round(mres_pallets,1),
            "ugrs_short_tons":round(ugrs_short_tons,1),
            "ugr_twenty_ft_teus":round(ugr_twenty_ft_teus,1)
            }


def get_class_one_water_bottled(pax=1, planning_factor=2):
    min_gallons = pax * planning_factor
    min_bottles = (min_gallons * 3.785) * 2
    min_cases = min_bottles / 24
    min_pallets = min_cases / 72
    min_short_tons = min_pallets * 2182 / 2000
    twenty_ft_teus =  min_pallets / 16

    return {"gallons":round(min_gallons,1),
            "bottles":round(min_bottles,1), 
            "cases":round(min_cases,1), 
            "pallets":round(min_pallets,1), 
            "short_tons":round(min_short_tons,1), 
            "twenty_ft_teus":round(twenty_ft_teus,1)
            }



def get_class_one_water_bulk(pax=1, planning_factor=1):
    min_gallons = pax * planning_factor
    min_short_tons = (min_gallons * 8.34) / 2000

    return {"gallons":round(min_gallons,1),
            "short_tons":round(min_short_tons,1) 
            }

This is used in the views

def exercise_detail(request, pk, *args, **kwargs):
    ex_name = Exercises.objects.get(pk=pk)
    ex_personnel = ExercisePersonnel.objects.filter(exercise_id=pk)
    planners = ExercisePermissions.objects.filter(exercise=pk)
    user_list = MlptUsers.objects.order_by('email')
    unit_list_planner = Units.objects.order_by('unit_name')
    unit_list, chow_list, bottled_water_list, bulk_water_list = {}, {}, {}, {}

    # generate dictionaries so you can parse in template
    for unit in ex_personnel:
        unit_list[f"{unit}"] = unit.quantity
        chow_list[f"{unit}"] = get_class_one_chow(pax=unit.quantity)
        bottled_water_list[f"{unit}"] = get_class_one_water_bottled(
            pax=unit.quantity)
        bulk_water_list[f"{unit}"] = get_class_one_water_bulk(
            pax=unit.quantity)

    context = {
        'ex_name': ex_name,
        'chow_list': chow_list,
        'bottled_water_list': bottled_water_list,
        'bulk_water_list': bulk_water_list,
        'unit_list': unit_list,
        'planners': planners,
        'user_list': user_list,
        'unit_list_planner': unit_list_planner,
    }

    return render(request, 'exercise/exercise_detail.html', context)

However, I can't get the tabs working correctly in the template.

I can create the tables and use a for loop to create a new line for each key in the dictionary "unit_list" which displays all the info, but I don't want it in one place, which looks like this.

<h3>
  PLANNING DATA
  <small class="text-muted">numbers are per day</small>
</h3>
<ul class="nav nav-tabs" id="myTab" role="tablist">
  {% for key,value in unit_list.items %}
  <li class="nav-item" role="presentation">
    <button class="nav-link active" id="{{key}}-tab" data-bs-toggle="tab" data-bs-target="#{{key}}" type="button" role="tab" aria-controls="home" aria-selected="true"> {{key}} </button>
  </li>
  {% endfor %}
</ul>
<div class="tab-content" id="myTabContent">
  <div class="tab-pane fade show active" id="{{key}}" role="tabpanel" aria-labelledby="home-tab">
    <div class="row">
      <div class="col">

        <div class="card text-dark bg-light mb-3" >
          <div class="card-header">CLASS I - WATER (BOTTLED)</div>
          <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col text-center">UNIT</th>
              <th scope="col text-center">GAL</th>
              <th scope="col text-center">BTL</th>
              <th scope="col text-center">CASES</th>
              <th scope="col text-center">PLTS</th>
              <th scope="col text-center">STONS</th>
              <th scope="col text-center">20TEUS</th>
            </tr>
          </thead>
          <tbody>

            {%for key, value in bottled_water_list.items %}
            <tr>
              <td class="">{{key}}</td>
              <td class="">{{value.gallons}}</td>
              <td class="">{{value.bottles}}</td>
              <td class="">{{value.cases}}</td>
              <td class="">{{value.pallets}}</td>
              <td class="">{{value.short_tons}}</td>
              <td class="">{{value.twenty_ft_teus}}</td>
            </tr> 
            {%endfor%}
          </tbody>
        </table>
      </div>
    </div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - WATER (BULK)</div>
      <div class="card-body">
    <table class="table table-striped table-hover table-sm">
      <thead class="">
        <tr>
          <th scope="col">UNIT</th>
          <th scope="col">GAL</th>
          <th scope="col">STONS</th>
        </tr>
      </thead>
      <tbody>

        {%for key, value in bulk_water_list.items %}
        <tr>
          <td class="">{{key}}</td>
          <td class="">{{value.gallons}}</td>
          <td class="">{{value.short_tons}}</td>
        </tr> 
        {%endfor%}
      </tbody>
    </table>
  </div>
</div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - CHOW</div>
      <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col">UNIT</th>
              <th scope="col">CASES</th>
              <th scope="col">PLTS</th>
              <th scope="col">STONS</th>
              <th scope="col">20TEUS</th>
              <th scope="col">UGR PLTS</th>
              <th scope="col">MRE PLTS</th>
              <th scope="col">UGR STON</th>
              <th scope="col">UGR 20TEUS</th>
            </tr>
          </thead>
          <tbody>

            {%for key, value in chow_list.items %}
            <tr>
              <td class="">{{key}}</td>
              <td class="">{{value.cases}}</td>
              <td class="">{{value.pallets}}</td>
              <td class="">{{value.short_tons}}</td>
              <td class="">{{value.twenty_ft_teus}}</td>
              <td class="">{{value.ugrs_pallets}}</td>
              <td class="">{{value.mres_pallets}}</td>
              <td class="">{{value.ugrs_short_tons}}</td>
              <td class="">{{value.ugr_twenty_ft_teus}}</td>
              
            </tr> 
            {%endfor%}
          </tbody>
        </table>               
      </div>
    </div>
      </div>
    </div>
  </div>
</div>

This is the template and how I've been attempting to accomplish the same thing with separate tabs.

<h3>
  PLANNING DATA
  <small class="text-muted">numbers are per day</small>
</h3>
<ul class="nav nav-tabs" id="myTab" role="tablist">
  {% for key,value in unit_list.items %}
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="{{key}}-tab" data-bs-toggle="tab" data-bs-target="#{{key}}" type="button" role="tab" aria-controls="{{key}}" aria-selected="true"> {{key}} </button>
  </li>
  {% endfor %}
</ul>
<div class="tab-content" id="myTabContent">
  {% for key,value in unit_list.items %}
  <div class="tab-pane fade" id="{{key}}" role="tabpanel" aria-labelledby="{{key}}-tab">
    <div class="row">
      <div class="col">

        <div class="card text-dark bg-light mb-3" >
          <div class="card-header">CLASS I - WATER (BOTTLED)</div>
          <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col text-center">UNIT</th>
              <th scope="col text-center">GAL</th>
              <th scope="col text-center">BTL</th>
              <th scope="col text-center">CASES</th>
              <th scope="col text-center">PLTS</th>
              <th scope="col text-center">STONS</th>
              <th scope="col text-center">20TEUS</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td class="">{{key}}</td>
              <td class="">{{value.gallons}}</td>
              <td class="">{{value.bottles}}</td>
              <td class="">{{value.cases}}</td>
              <td class="">{{value.pallets}}</td>
              <td class="">{{value.short_tons}}</td>
              <td class="">{{value.twenty_ft_teus}}</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - WATER (BULK)</div>
      <div class="card-body">
    <table class="table table-striped table-hover table-sm">
      <thead class="">
        <tr>
          <th scope="col">UNIT</th>
          <th scope="col">GAL</th>
          <th scope="col">STONS</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td class="">{{key}}</td>
          <td class="">{{value.gallons}}</td>
          <td class="">{{value.short_tons}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - CHOW</div>
      <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col">UNIT</th>
              <th scope="col">CASES</th>
              <th scope="col">PLTS</th>
              <th scope="col">STONS</th>
              <th scope="col">20TEUS</th>
              <th scope="col">UGR PLTS</th>
              <th scope="col">MRE PLTS</th>
              <th scope="col">UGR STON</th>
              <th scope="col">UGR 20TEUS</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td class="">{{key}}</td>
              <td class="">{{value.cases}}</td>
              <td class="">{{value.pallets}}</td>
              <td class="">{{value.short_tons}}</td>
              <td class="">{{value.twenty_ft_teus}}</td>
              <td class="">{{value.ugrs_pallets}}</td>
              <td class="">{{value.mres_pallets}}</td>
              <td class="">{{value.ugrs_short_tons}}</td>
              <td class="">{{value.ugr_twenty_ft_teus}}</td>
              
            </tr> 
          </tbody>
        </table>               
      </div>
    </div>
      </div>
    </div>
  </div>
  {%endfor%}
</div>

This is the source code of the webpage when I run it.

<h3>
  PLANNING DATA
  <small class="text-muted">numbers are per day</small>
</h3>
<ul class="nav nav-tabs" id="myTab" role="tablist">
  
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="31st MEU-tab" data-bs-toggle="tab" data-bs-target="#31st MEU" type="button" role="tab" aria-controls="31st MEU" aria-selected="true"> 31st MEU </button>
  </li>
  
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="7th Comm Bn-tab" data-bs-toggle="tab" data-bs-target="#7th Comm Bn" type="button" role="tab" aria-controls="7th Comm Bn" aria-selected="true"> 7th Comm Bn </button>
  </li>
  
</ul>
<div class="tab-content" id="myTabContent">
  
  <div class="tab-pane fade" id="31st MEU" role="tabpanel" aria-labelledby="31st MEU-tab">
    <div class="row">
      <div class="col">

        <div class="card text-dark bg-light mb-3" >
          <div class="card-header">CLASS I - WATER (BOTTLED)</div>
          <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col text-center">UNIT</th>
              <th scope="col text-center">GAL</th>
              <th scope="col text-center">BTL</th>
              <th scope="col text-center">CASES</th>
              <th scope="col text-center">PLTS</th>
              <th scope="col text-center">STONS</th>
              <th scope="col text-center">20TEUS</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td class="">31st MEU</td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - WATER (BULK)</div>
      <div class="card-body">
    <table class="table table-striped table-hover table-sm">
      <thead class="">
        <tr>
          <th scope="col">UNIT</th>
          <th scope="col">GAL</th>
          <th scope="col">STONS</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td class="">31st MEU</td>
          <td class=""></td>
          <td class=""></td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - CHOW</div>
      <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col">UNIT</th>
              <th scope="col">CASES</th>
              <th scope="col">PLTS</th>
              <th scope="col">STONS</th>
              <th scope="col">20TEUS</th>
              <th scope="col">UGR PLTS</th>
              <th scope="col">MRE PLTS</th>
              <th scope="col">UGR STON</th>
              <th scope="col">UGR 20TEUS</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td class="">31st MEU</td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              
            </tr> 
          </tbody>
        </table>               
      </div>
    </div>
      </div>
    </div>
  </div>
  
  <div class="tab-pane fade" id="7th Comm Bn" role="tabpanel" aria-labelledby="7th Comm Bn-tab">
    <div class="row">
      <div class="col">

        <div class="card text-dark bg-light mb-3" >
          <div class="card-header">CLASS I - WATER (BOTTLED)</div>
          <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col text-center">UNIT</th>
              <th scope="col text-center">GAL</th>
              <th scope="col text-center">BTL</th>
              <th scope="col text-center">CASES</th>
              <th scope="col text-center">PLTS</th>
              <th scope="col text-center">STONS</th>
              <th scope="col text-center">20TEUS</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td class="">7th Comm Bn</td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - WATER (BULK)</div>
      <div class="card-body">
    <table class="table table-striped table-hover table-sm">
      <thead class="">
        <tr>
          <th scope="col">UNIT</th>
          <th scope="col">GAL</th>
          <th scope="col">STONS</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td class="">7th Comm Bn</td>
          <td class=""></td>
          <td class=""></td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
    <div class="card text-dark bg-light mb-3" >
      <div class="card-header">CLASS I - CHOW</div>
      <div class="card-body">
        <table class="table table-striped table-hover table-sm">
          <thead class="">
            <tr>
              <th scope="col">UNIT</th>
              <th scope="col">CASES</th>
              <th scope="col">PLTS</th>
              <th scope="col">STONS</th>
              <th scope="col">20TEUS</th>
              <th scope="col">UGR PLTS</th>
              <th scope="col">MRE PLTS</th>
              <th scope="col">UGR STON</th>
              <th scope="col">UGR 20TEUS</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td class="">7th Comm Bn</td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              <td class=""></td>
              
            </tr> 
          </tbody>
        </table>               
      </div>
    </div>
      </div>
    </div>
  </div>
  
</div>

     </div>
  </div>

So none of the data populates into the tables when I use the for loop in this way and the html for the tables is greyed out when I inspect it, and clicking the tabs does not make it appear.

It looks like thisenter image description here

I believe this means I am somehow not successfully linking the tab id to the tab content id even though the ids match and I also don't know how the context is passed when I run the for loop on individual tables, but not the whole thing.

0 Answers
Related