Search code examples
pythonmongodbdjango-filterdjango-tables2

How to filter django-tables2 after populating it with list of dicts rather than a query set?


I have a list of dicts that I fetch from MongoDB. Then I populate django-tables2 table in views.py and render it in my template index.html

In views.py

from django.shortcuts import render

from .tables import generateTable
from django_tables2 import RequestConfig

import pymongo
import pandas as pd
import json

client = pymongo.MongoClient("<mongodb url>")
db = client["stocks"]
col = db["company_stocks"]
the_rows = col.find({}, {'_id': False})

pandas_dataframe = pd.DataFrame(list(the_rows), columns=['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Name'])

json_fomatted = pandas_dataframe.to_json(orient='records')

data = []
data = json.loads(json_fomatted)

def index(request):
    table = generateTable(data)
    RequestConfig(request).configure(table)

    context = {'stocks_table': table }

    return render(request, "home_app/index.html", context)

tables.py

import django_tables2 as tables
from .models import Stocks

class generateTable(tables.Table):
    Date = tables.Column()
    Open = tables.Column()
    High = tables.Column()
    Low = tables.Column()
    Close = tables.Column()
    Volume = tables.Column()
    Name = tables.Column()

urls.py

urlpatterns = [
    # Uncomment the next line to enable the admin:
    path('admin/', admin.site.urls),
    url(r'^$', home_app.views.index, name='index'),
    url(r'^home$', home_app.views.index, name='home'),
]

index.html

{% load render_table from django_tables2 %}
{% render_table stocks_table 'django_tables2/bootstrap.html' %}

Result is this

Now I am trying to filter the table with django-filter but with not luck

What I found was how to filter data that had been populated with queryset rather than list of dicts

My attempt at filtering:

views.py

...
from .models import Stocks
...

def index(request):
    table = generateTable(data)
    RequestConfig(request).configure(table)

    #with this line
    myFilter = stockFilter(request.GET, queryset=Stocks.objects.all())

    context = {'stocks_table': table, 'myFilter': myFilter }

    return render(request, "home_app/index.html", context)

filters.py

import django_filters

from .models import Stocks

class stockFilter(django_filters.FilterSet):
    class Meta:
        model = Stocks
        fields = '__all__'

models.py

from django.db import models

class Stocks(models.Model):
    open = models.IntegerField(
        max_length = 128)
    high = models.IntegerField(
        max_length = 128)
    low = models.IntegerField(
        max_length = 128)
    close = models.IntegerField(
        max_length = 128)
    volume = models.IntegerField(
        max_length = 128)
    name = models.CharField(
        max_length = 128)

index.html

<form method="GET">
   {{ myFilter.form }}
   <input type="submit" />
</form>
{% load render_table from django_tables2 %}
{% render_table stocks_table 'django_tables2/bootstrap.html' %}

Here is the result

And after filtering...

I think the problem is the fact that my tables are populated with a list rather than a queryset.

Is there a better way of filtering django-tables2?

Any help is much appreciated!

I found a similar question posted but it uses multiple models for its tables


Solution

  • What I ended up doing was after getting the desired documents from mongo, I created a model object Stocks and appended that to a list and simply bulk_create(created list)

    views.py

    the_rows = col.find({}, {'_id': False})
    
    json_data = list(the_rows)
        
    obj_list = []
    for data in json_data:
        _open = round(float(data['Open']), 2)
        _high = round(float(data['High']), 2)
        _low = round(float(data['Low']), 2)
        _close = round(float(data['Close']), 2)
    
        obj = Stocks(name=data['Name'], date=data['Date'], open=_open, high=_high, low=_low, close=_close, volume=data['Volume'])
    
        obj_list.append(obj)
    
    Stocks.objects.bulk_create(obj_list)
    

    tables.py is based off of models.py

    import django_tables2 as tables
    from .models import Stocks
    
    class generateTable(tables.Table):
        class Meta:
            model = Stocks;
            template = 'django_tables2/bootstrap.html';
    

    Then to create the table and filter, I followed steps I found here

    views.py

    qs = Stocks.objects.all()
    
    myFilter = stockFilter(request.GET, queryset=qs)
    
    table = generateTable(myFilter.qs)
    RequestConfig(request, paginate={"per_page": 30}).configure(table)
    
    return render(request, "home_app/index.html", { 'stocks_table': table, 'myFilter': myFilter })
    

    And finally the template index.html

    {% block content %}
    {% load render_table from django_tables2 %}
    <div class="row">
        <div class="filter_column">
            <form>
                {{myFilter.form}}
                <input type="submit" />
            </form>
        </div>
        <div class="table_column">
            {% render_table stocks_table %}
        </div>
    </div>
    
    {% endblock %}
    

    Result