Search code examples
pythonjquerydjangodatepickerdjango-filter

combine django-filter DateTimeFromToRangeFilter and DateTimeInput(datepicker)


Using django_filter and datetimeinput as a datepicker, I am trying to add a date and time input, a FROM, and TO fields.

I have only been able to use a dateinput with just one field from django forms or from django filter DateTimeFromToRangeFilter without the date picker showing (just manual text entry).

Here is my filter_model.py for the one field with a date picker.

from app.models.api_status import ApiStatus
import django_filters
from django import forms

class DateTimeInput(forms.DateTimeInput):
    input_type = 'date'

    # working solution for just 1 date field
class ApiStatusFilter(django_filters.FilterSet):
    date_time = django_filters.DateFilter(
        label=('With start date'),
        lookup_expr=('icontains'), # use contains,
        widget=DateTimeInput()
    )
    class Meta:
        model = ApiStatus
        fields = ['id', 'date_time']

Picture shows a clickable date picker popup.

enter image description here

Here is my filter_model.py for the two fields, FROM and TO without a date picker.

from app.models.api_status import ApiStatus
import django_filters
from django import forms

class DateTimeInput(forms.DateTimeInput):
    input_type = 'date'


class ApiStatusFilter(django_filters.FilterSet):
    date_time =django_filters.DateTimeFromToRangeFilter()

    class Meta:
        model = ApiStatus
        fields = ['id', 'date_time']
        widgets = {
            'date_time': forms.DateTimeInput(attrs={'placeholder':'Select a date'})
        }

Picture below shows a manual text input without a datepicker popup. enter image description here

Here is my template file although I didn't alter it much when trying the two approaches above. status_template.html

{% load static %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <link rel="stylesheet" type="text/css" href="{% static 'css/table_styling.css' %}">
        <meta charset="UTF-8">
        <title>Test Site</title>
        {% comment %}
        <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
        <link rel="stylesheet" href="/resources/demos/style.css"> 
        <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
        {% endcomment %}
    </head>

    <body>
        <table>
            <thead>
                <tr>
                    {% for keys in dictionarys.keys %} 
                        <th>{{ keys }}</th>
                    {% endfor %}
                </tr>
            </thead>
            <tbody>
                <form method="get">
                    {{ apistatus_filter.form.as_p }}
                    <button type="submit">Search</button>
                        {% for user in dataqs.object_list %}
                        <tr>
                            <td>{{ user.id }}</td>
                            <td>{{ user.date_time }}</td>
                        {% endfor %}
                </form>
            </tbody>
        </table>
        {% comment %} <script>
            $( function() {
            $("#datepicker").datepicker();
            } );
        </script> {% endcomment %}
    </body>
</html>

I did look into a variety of sources on here and elsewhere. I tried using MultiWidget and jQuery but didn't get those working yet. Thoughts? Thanks in advance.


Solution

  • I was able to solve it using no external dependencies (no jquery), just used datetime-local input and DateTimeFromToRangeFilter with Range widget. Perhaps not the most ideal solution, but it is one way to do this.

    My model, filter, view, and template codes are below.

    model.py

    from app.modules.string_handler import StringHandler
    from django.db.models.signals import post_save
    import datetime
    
    class ApiStatus(models.Model):
        id = models.AutoField(primary_key=True)
        date_time = models.DateTimeField("Date_Time", default=datetime.datetime.now(), blank=True)
    
        class Meta:
            managed = True
            db_table = 'api_status'
            verbose_name = 'API STATUS'
    
        def __str__(self):
            "A string representation of the model."
            return f'{self.id},{self.token},{self.date_time},{self.status},{self.summary},{self.log}'
    
        def __unicode__(self):
            return self.created_at
    

    filter.py

    from app.models.api_status import ApiStatus
    import django_filters
    from django import forms
    
    class ApiStatusFilter(django_filters.FilterSet):
    
        date_time = django_filters.DateTimeFromToRangeFilter(
            lookup_expr=('icontains'),
            widget=django_filters.widgets.RangeWidget(
                attrs={'type':'datetime-local'}
            )
        )
    
        class Meta:
            model = ApiStatus
            fields = ['id', 'date_time']
    

    view.py

    from django.shortcuts import render
    from app.models.filters_model import ApiStatusFilter
    from app.models.api_status import ApiStatus
    import requests
    from django import forms
    
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    import urllib
    from datetime import datetime, timedelta
    
    def status(request):
        apistatus_list = ApiStatus.objects.all()
    
        request.GET2 = request.GET.copy()
    
        if request.GET2.get('date_time_min'):
            request.GET2['date_time_min'] = datetime.strptime(request.GET2['date_time_min'],"%Y-%m-%dT%H:%M").strftime("%Y-%m-%d %H:%M")
        if request.GET2.get('date_time_max'):
            request.GET2['date_time_max'] = datetime.strptime(request.GET2['date_time_max'],"%Y-%m-%dT%H:%M").strftime("%Y-%m-%d %H:%M")
    
        apistatus_filter = ApiStatusFilter(request.GET2, queryset=apistatus_list)
    
        paginator = Paginator(apistatus_filter.qs, 10)
        page = request.GET.get('page')
    
        try:
            dataqs = paginator.page(page)
        except PageNotAnInteger:
            dataqs = paginator.page(1)
        except EmptyPage:
            dataqs = paginator.page(paginator.num_pages)
    
        return render(request, 'status_page_template.html', {'table_col_DATA':all_entries_ordered, 'dictionarys': dictionarys, 'apistatus_filter': apistatus_filter, 'dataqs': dataqs, 'allobjects': apistatus_list})
    

    template.html

    {% load my_templatetags %}
    
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <link rel="stylesheet" type="text/css" href="{% static 'css/search_form_table_styling.css' %}">
            <meta charset="UTF-8">
            <title>TEST Site</title>
        </head>
    
        <body>
            <form method="get" action="">
                <div class="search_form_wrapper">
                    <div class="id_box">ID:{{ apistatus_filter.form.id }}</div>
                    <div class="id_box">Date_Time:{{ apistatus_filter.form.date_time }}</div>
                </div>
    
                <input type="submit" value="Submit" class="search_form_submit">
            </form>
    
            <table>
                <tbody>
                    {% for user in dataqs.object_list %}
                        <tr>
                            <td>{{ user.id }}</td>
                            <td>{{ user.date_time }}</td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
    
            <div class="pagination">
                <span>
                    {% if dataqs.has_previous %}
                        <a href="?{% query_transform request page=1 %}">&laquo; first</a>
                        <a href="?{% query_transform request page=dataqs.previous_page_number %}">previous</a>
                    {% endif %}
    
                    <span class="current">
                        Page {{ dataqs.number }} of {{ dataqs.paginator.num_pages }}.
                    </span>
    
                    {% if dataqs.has_next %}
                        <a href="?{% query_transform request page=dataqs.next_page_number %}">next</a>
                        <a href="?{% query_transform request page=dataqs.paginator.num_pages %}">last &raquo;</a>
                    {% endif %}
                </span>
            </div> 
        </body>
    </html>