0

I have a page on my Django website, which is displaying a number of tables based on information stored in the database.

The view being used to create the page displaying the tables is defined with:

def current_budget(request, budget_id):
    """ View the active provisional/deposit budget """
    budget = Budget.objects.select_related('project',     'project__budget_overview').prefetch_related('project__projectroom_set', 'project__budget_versions', 'budget_items').get(id=budget_id)
    project = budget.project
    # project.projectroom_set.filter(budgetitem__isnull=True, cciitem__isnull=True).delete()

    if project.budget_overview.deposit_budget_saved: return HttpResponseRedirect(reverse('costing:combined_budget', args=[project.id]))

    #This is now done in the costing_home view
    # if not budget:
    #   Budget.objects.create(project=project, current_marker=1)

    if not budget.budget_items.exists() and not project.budget_overview.deposit_budget_saved: init_budget(budget) # Create initial BudgetItem objects as standard
    budget_items = budget.budget_items.select_related('budget', 'budget__project', 'project_room', 'project_room__room', 'room')#.order_by('build_type', 'build_type_detail', 'project_room', 'order') # .exclude(build_type=None)
    budget_items2 = None #budget.budget_items.filter(build_type=None).order_by('build_type_detail', 'project_room', 'room')

    context = {
        'project': project,
        'budget': budget,
        'offset1': -5,
        'offset2': -4,
        }

    try: context['current_budget'] = project.budget_versions.get(current_marker=1) #For option name/date on top of pdfs
    except ObjectDoesNotExist: pass

    if request.GET.get('version') or project.budget_overview.deposit_budget_saved: #Make the fields all readonly
        context['readonly'] = True
        context['offset1'] = -7

    if request.GET.get('report'): #Schedule of works report uses same data as current budget form
        """ Client view of budget. IMPORTANT: Hidden items are not displayed here """

        items_grouped = groupby(budget_items.filter(hidden_cost=False), lambda x: x.build_type)
        grouped_items = [(x, list(y)) for x, y in items_grouped]
        context['grouped_items'] = grouped_items
        if request.GET.get('pdf'):
            template = get_template('costing/report_schedule_of_works.html')
            html  = template.render(context)

            file = open('test.pdf', "w+b")
            pisaStatus = pisa.CreatePDF(html.encode('utf-8'), link_callback=fetch_resources, dest=file,
                encoding='utf-8')

            file.seek(0)
            pdf = file.read()
            file.close()            
            return HttpResponse(pdf, 'application/pdf')
        else:
            context['webview'] = 1
            context['html'] = render_to_string('costing/report_schedule_of_works.html', context)
            context['active_tab'] = '3'
            return render(request, 'costing/reports_pre_deposit.html', context)

    else:
        if not context.get('readonly'):
            context['skill_day_rate'] = skill_day_rate
            context['labour_day_rate'] = labour_day_rate
        # Dict with ProjectRoom ids and the total for the room
        room_totals = {}

        for project_room in project.projectroom_set.all():
            room_totals[project_room.id] = sum(item.total_inc_profit for item in budget_items if item.project_room == project_room)

        context['room_totals'] = room_totals

        item_formset = BudgetItemFormset(queryset=budget_items, form_kwargs={'project': project})
        item_form = item_formset.forms[0]
        context['field_count'] = len(item_form.visible_fields())
        context['ao_field_count'] = len(item_form.visible_fields())

        room_choices = project.room_choices

        context['formset'] = item_formset
        context['widths'] = budget_item_column_widths #First column is add/delete options to allow for forloop count offset
        context['options_width'] = options_width #First column is add/delete options to allow for forloop count offset
        context['labour_rate'] = labour_day_rate
        context['skill_rate'] = skill_day_rate
        context['item_code_options'] = ItemCodeForm()
        skill_total = int(budget_items.aggregate(Sum('skill_days'))['skill_days__sum'] or 0)
        if budget_items2: labour_total = int(budget_items2.aggregate(Sum('labour_days'))['labour_days__sum'])
        else: labour_total =  0

        return render(request, 'costing/budget_current.html', context)

I now want to add a 'custom' column to these tables, to allow the user to enter their own notes in (i.e. one that will not be displaying data retrieved from the database, but which should add information to each row in the database when it is saved).

How would I do this? I would have thought that I will do it in the view (Python), rather than in the template (HTML), since the view is where the tables are being constructed?

Edit

So, I've added the extra field to the model in models.py for the app:

class Deposit(models.Model):
    """ Each Deposit is linked to a Payment, whose is_booking_deposit field = True """
    project = models.OneToOneField('projects.Project', null=True, blank=True)
    half_paid = models.DateField(null=True, blank=True)
    date_received = models.DateField(null=True, blank=True)
    amount_exc_vat = models.DecimalField(decimal_places=2, max_digits=12, null=True, blank=True)
    invoice_raised = models.DateField(null=True, blank=True)
    notes = models.TextField(null=True, blank=True)
    # Create a column for 'custom notes' in the tables:
    custom_notes = models.TextField(null=True, blank=True) #Add the column to table in tables.py

    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    payment = models.OneToOneField(Payment, null=True)
    ...

The field that I've added to the Deposit model above is the custom_notes one.

I also tried adding the same field to the BudgetItemTable() in tables.py:

class BudgetItemTable(tables.Table):
    # Add a column for 'custom notes' to the tables for current budget
    custom_notes = tables.Column(accessor='self.custom_notes')
    class Meta:
        model = BudgetItem
        attrs = {"class": "paleblue"}
        exclude = ('id')

I've run python manage.py makemigrations & python manage.py migrate myApp, but when I refresh my browser to view this page again, the new column for my table is not displayed- do I need to add it to the view somehow? How would I do this?

Edit

The HTML file for the view that displays the table I want to add a column to has the following structure:

...
{% block page_options_style %}allow-footer{% endblock page_options_style %}
{% block page_options %}
    ...
    {% block report %}
    <div id='budget_form' class="col-12" data-pr="{{project.id}}" style="margin-bottom:7em;">
        <form class="autosave_form formset num_refresh text-sm" data-view-url="{% url 'costing:save_items' budget.id %}">{% csrf_token %}
            {{formset.management_form}}
            <div>
                <table ...>
                    <thead class=... >
                        <tr class=...>
                            ...
                            <!--  code to get table headings here -->
                            <th style="width:{{options_width}}">Custom Notes</th>
                            <!-- I added the 'Custom Notes' heading myself -->
                        </tr>
                    </thead>
                    ...
                    <tbody>
                        ...
                        <tr id="item_{{forloop.counter}}" class="{% cycle 'odd' 'even' %}">
                            ...
                            <!-- code add columns and populate rows here -->
                            <td>
                                <a class="delete" ... ></a>
                                <!-- I can see this column with the 'delete' values is the last column in the table on the webpage, so I want to manually add another column after it in the table- I tried doing this by adding the following tags: -->
                            </td>
                            <td>
                                <a class="custom_notes" type="text" value=""></a>
                            </td>
                            ...
                        </tr>
                    </tr>
                </tbody>
            </table>
            ...
        </tbody>
    </table>
</div>
</form>    

I tried to add the 'Custom Notes' column to the table with the lines:

<td>
    <a class="custom_notes" type="text" value=""></a>
</td>

When I view this page in the browser, I can see the Custom Notes column heading that I've added, displayed above the table, but it is displayed just to the right of where the table ends (I expected the column that I added to the table to be displayed below it).

The table column for 'custom notes' that I have tried adding is not displayed in the table at all...

Why is this? How can I get the new column to be displayed in the table on the webpage? I've added the corresponding field to the model in models.py, so although there won't be any data in this field for any of the items in the database at the moment, when the user enters data in this field in the table, there is somewhere for those values to be stored in the model in the database...

Edit

I managed to add this additional field to the table by appending the following HTML to the table, just inside the last two </tr> tags, inside </tbody></table>:

<td>
    <a class="custom_notes" type="text" value=""></a>
    <input id="budget_notes" type="text" width="100" value="">
</td>

But for some reason, the text input field that I have added is very narrow- you can't see more than a few characters of text at a time when typing into it. I tried specifying the width of the field using width="100", as shown above, but this doesn't appear to have made any difference. How can I force the cells in this column to have a set width?

Noble-Surfer
  • 3,052
  • 11
  • 73
  • 118
  • There should be a file, typically named "models" in your project. It would define tables - this is where you need to start. Define an extra column there, run "makemigrations" and "migrate" to update, and then point to it in your views. – postoronnim Nov 28 '16 at 20:43
  • Looking through the `models.py` file for this app, I don't think the tables themselves are actually defined in the `models.py` file, but each of the tables hold a number of instances of classes that are defined in `models.py`, i.e. I have a class `Deposit` in `models.py`, and in the web page I'm looking at, there is a table for 'Deposits', which has a column for each of the attributes of the class, plus a few other columns. – Noble-Surfer Nov 29 '16 at 09:59
  • The app has a `tables.py` file, which appears to be where the tables are defined, however, the tables show a lot more information in the web page than what their definitions here appear to indicate they will display. Would this be where I want to add my custom column? – Noble-Surfer Nov 29 '16 at 09:59
  • Yes, don't forget to add defaults with the column definition because you are adding a new field on top of existing data. This post here talks about adding a field and running migrations. http://stackoverflow.com/questions/24311993/how-to-add-a-new-field-to-a-model-with-new-django-migrations – postoronnim Nov 29 '16 at 15:47

0 Answers0