Part 1
I had my datatable working with obj iteration but I am moving to DRF-datatables.. and although I got the example site running no problem the actual implementation on my end is kicking my butt. Basically, I got my whole weekend to show a table that seems to be loading data (as pagination is showing the proper info) but my rows are all blank: https://i.stack.imgur.com/19LPp.png
Then I tried to add the "columns" section in the scripts and that breaks the whole table: https://i.stack.imgur.com/1Ln4A.png
If I change the ajax call to
"ajax": "/api/entry/?format=datatables",
then I get the most closely working table: https://i.stack.imgur.com/KvAtK.png - however the problem remains that the rows are empty and if I add the cols then everything breaks.
Where am I going wrong? I'm also not getting any error messages so it's hard to debug datatables.
Maybe Part 2..
Do I even need to go for DRF-datatables? My end goal is to be able to select multiple rows and then edit the trade for all those entries.
Example of the end goal
- Select 3 trade
- Click dropdown somewhere at the top of the table
- Select Trade PK from that dropdown
- Click Save
- Table shows the latest data
entry_list.html
{% extends "dashboard/base.html" %}
{% load i18n %}
{% block content %}
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h2 class="text-gray-800">{% block title %}{% trans "Imported Entries" %}{% endblock %}</h2>
<a role="button" class="btn btn-success" href="{% url 'import' %}"><i
class="fas fa-plus-circle"></i> Import New Entires</a>
</div>
<!-- Content Row -->
<div class="row">
<div class="col-md-12">
<table id="entrytable"
class="table-hover table display"
align="center"
style="width:100%">
<thead>
<tr role="row">
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">ID
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Date
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Trade
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Type
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Symbol
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Amount
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Price
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Fee
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Reg Fee
</th>
<th class="sorting" tabindex="0" aria-controls="dataTable" rowspan="1"
colspan="1" aria-label="" style="">Ref
</th>
</tr>
</thead>
</table>
</div>
</div>
{% endblock %}
{% block js %}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/css/bootstrap.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/dataTables.bootstrap4.min.css"/>
<!--https://datatables.net/examples/server_side/select_rows.html-->
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.min.css"/>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.22/js/dataTables.bootstrap4.min.js"></script>
<script>
$(document).ready(function() {
var selected = [];
$("#entrytable").DataTable({
"order": [[ 1, "desc" ]],
"processing": true,
"serverSide": true,
"ajax": {
"url": "/api/entry/?format=datatables",
"type": "POST",
"beforeSend": function(xhr) {
xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token|escapejs }}");
}
},
"columns": [
{"data": "pk"},
{"data": "date"},
{"data": "trade.id"},
{"data": "entry_type"},
{"data": "symbol"},
{"data": "amount"},
{"data": "price"},
{"data": "fee"},
{"data": "reg_fee"},
{"data": "transaction_id"},
]
"rowCallback": function( row, data ) {
if ( $.inArray(data.DT_RowId, selected) !== -1 ) {
$(row).addClass('selected');
}
}
});
$('#entrytable tbody').on('click', 'tr', function () {
var id = this.id;
var index = $.inArray(id, selected);
if ( index === -1 ) {
selected.push( id );
} else {
selected.splice( index, 1 );
}
$(this).toggleClass('selected');
} );
} );
</script>
{% endblock %}
Serializers.py
class EntrySerializer(serializers.ModelSerializer):
class Meta:
model = Entry
fields = '__all__'
Views.py
class EntryViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Entry.objects.all()
serializer_class = EntrySerializer
permission_classes = [permissions.IsAdminUser]
filter_backends = (DjangoFilterBackend, OrderingFilter,)
models.py
class Entry(models.Model):
ENTRY = 'entry'
EXIT = 'exit'
ENTRY_TYPE_CHOICES = [
(ENTRY, 'Entry'),
(EXIT, 'Exit'),
# (DIVIDEND_RECEIVED, 'Dividend Received'),
# (DIVIDEND_SOLD, 'Dividend Sold'),
]
class Meta:
verbose_name = "Entry"
verbose_name_plural = "Entries"
trade = models.ForeignKey(Trade, on_delete=models.CASCADE, null=True, blank=True)
date = models.DateTimeField(null=True, blank=True, default=datetime.datetime.now)
amount = models.FloatField(null=True)
price = models.FloatField(null=True)
fee = models.FloatField(null=True, blank=True)
entry_type = models.CharField(max_length=5, choices=ENTRY_TYPE_CHOICES, default=ENTRY)
reg_fee = models.FloatField(null=True, blank=True)
transaction_id = models.CharField(max_length=100, null=True, blank=True)
symbol = models.ForeignKey(Symbol, on_delete=models.SET_NULL, blank=True, null=True)
created_by = models.ForeignKey(User, null=True, blank=True, editable=False, on_delete=models.CASCADE)