Enhance filtering functionality and UI consistency across user-related views by implementing a generic search filter and updating filter display in templates.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import django_filters
|
||||
from django.db.models import Q
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
@@ -34,6 +36,8 @@ class CidUserFilter(django_filters.FilterSet):
|
||||
return parent
|
||||
|
||||
class UserUserFilter(django_filters.FilterSet):
|
||||
# Generic search across name and email/username
|
||||
q = django_filters.CharFilter(method='filter_search', label='Search')
|
||||
userprofile__grade = django_filters.ModelChoiceFilter(queryset=UserGrades.objects.all(),label="Grade")
|
||||
userprofile__supervisor = django_filters.ModelChoiceFilter(queryset=Supervisor.objects.all(), label="Supervisor")
|
||||
userprofile__peninsula_trainee = django_filters.BooleanFilter(label="Peninsula Trainee")
|
||||
@@ -69,6 +73,47 @@ class UserUserFilter(django_filters.FilterSet):
|
||||
super(UserUserFilter, self).__init__(*args, **kwargs)
|
||||
self.form.initial['is_active'] = True
|
||||
|
||||
def filter_search(self, queryset, name, value):
|
||||
"""
|
||||
Generic search that matches first name, last name, email or username.
|
||||
"""
|
||||
v = (value or "").strip()
|
||||
if not v:
|
||||
return queryset
|
||||
|
||||
return queryset.filter(
|
||||
Q(first_name__icontains=v)
|
||||
| Q(last_name__icontains=v)
|
||||
| Q(email__icontains=v)
|
||||
| Q(username__icontains=v)
|
||||
)
|
||||
|
||||
def __post_init_reorder__(self):
|
||||
"""Internal helper to move the generic search 'q' to the front of the form fields."""
|
||||
try:
|
||||
fields = self.form.fields
|
||||
if 'q' in fields:
|
||||
new_order = ['q'] + [k for k in fields.keys() if k != 'q']
|
||||
self.form.fields = OrderedDict((k, fields[k]) for k in new_order)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Ensure reorder runs after initialization
|
||||
def __new__(cls, *args, **kwargs):
|
||||
instance = super(UserUserFilter, cls).__new__(cls)
|
||||
# attach a post-init hook to reorder form fields
|
||||
orig_init = instance.__init__
|
||||
|
||||
def wrapped_init(*a, **k):
|
||||
orig_init(*a, **k)
|
||||
try:
|
||||
instance.__post_init_reorder__()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
instance.__init__ = wrapped_init
|
||||
return instance
|
||||
|
||||
|
||||
class ExaminationFilter(django_filters.FilterSet):
|
||||
class Meta:
|
||||
|
||||
+15
-15
@@ -151,7 +151,7 @@ class FirstImageColumn(tables.Column):
|
||||
return format_html('<span title="{}">Invalid image url<span>', image_object)
|
||||
|
||||
|
||||
class CidUserTable(tables.Table):
|
||||
class CidUserTable(SelectionTable):
|
||||
cid = tables.LinkColumn(
|
||||
"cid_scores", args=[A("cid"), A("passcode")], orderable=True
|
||||
)
|
||||
@@ -163,7 +163,7 @@ class CidUserTable(tables.Table):
|
||||
# anatomy_exams = tables.ManyToManyColumn(verbose_name="Anatomy Exams")
|
||||
group = tables.Column(linkify=True)
|
||||
|
||||
selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
#selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
|
||||
emails = tables.Column(empty_values=(), orderable=False)
|
||||
|
||||
@@ -171,7 +171,7 @@ class CidUserTable(tables.Table):
|
||||
"generic:update_cid", text="Edit", args=[A("pk")], orderable=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
class Meta(SelectionTable.Meta):
|
||||
model = CidUser
|
||||
template_name = "django_tables2/bootstrap4.html"
|
||||
fields = (
|
||||
@@ -199,7 +199,7 @@ class CidUserTable(tables.Table):
|
||||
return format_html(record.email)
|
||||
|
||||
|
||||
class CidUserExamTable(tables.Table):
|
||||
class CidUserExamTable(SelectionTable):
|
||||
cid = tables.LinkColumn(
|
||||
"cid_scores", args=[A("cid"), A("passcode")], orderable=True
|
||||
)
|
||||
@@ -210,7 +210,7 @@ class CidUserExamTable(tables.Table):
|
||||
longs_exams = tables.ManyToManyColumn(verbose_name="Long Exams")
|
||||
anatomy_exams = tables.ManyToManyColumn(verbose_name="Anatomy Exams")
|
||||
|
||||
selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
#selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
|
||||
emails = tables.Column(empty_values=(), orderable=False)
|
||||
|
||||
@@ -218,7 +218,7 @@ class CidUserExamTable(tables.Table):
|
||||
"generic:update_cid", text="Edit", args=[A("pk")], orderable=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
class Meta(SelectionTable.Meta):
|
||||
model = CidUser
|
||||
template_name = "django_tables2/bootstrap4.html"
|
||||
fields = (
|
||||
@@ -256,7 +256,7 @@ class CidUserExamTable(tables.Table):
|
||||
# return format_html("""<a href="#" onclick="return window.create_popup_window('/longs/series/{}', 'Series')" >Popup</a>""", record.pk)
|
||||
|
||||
|
||||
class UserUserTable(tables.Table):
|
||||
class UserUserTable(SelectionTable):
|
||||
|
||||
user = tables.Column(
|
||||
linkify={"viewname": "account_profile", "args": [A("username")]},
|
||||
@@ -275,7 +275,7 @@ class UserUserTable(tables.Table):
|
||||
accessor=A("userprofile__supervisor"),
|
||||
)
|
||||
|
||||
selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
#selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
|
||||
edit = tables.Column(
|
||||
empty_values=(),
|
||||
@@ -294,7 +294,7 @@ class UserUserTable(tables.Table):
|
||||
|
||||
date_joined = tables.DateTimeColumn(format="Y/m/d")
|
||||
|
||||
class Meta:
|
||||
class Meta(SelectionTable.Meta):
|
||||
model = User
|
||||
template_name = "django_tables2/bootstrap4.html"
|
||||
fields = (
|
||||
@@ -348,7 +348,7 @@ class UserUserTable(tables.Table):
|
||||
record.email,
|
||||
)
|
||||
|
||||
class ExaminationTable(tables.Table):
|
||||
class ExaminationTable(SelectionTable):
|
||||
examination = tables.Column(
|
||||
linkify=("generic:examination_detail", {"pk": tables.A("pk")}),
|
||||
verbose_name="Condition",
|
||||
@@ -360,19 +360,19 @@ class ExaminationTable(tables.Table):
|
||||
delete = tables.LinkColumn(
|
||||
"generic:examination_delete", text="Delete", args=[A("pk")], orderable=False
|
||||
)
|
||||
selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
#selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
|
||||
# synonym = tables.ManyToManyColumn(verbose_name="Synonyms")
|
||||
#synonym = tables.Column(empty_values=())
|
||||
#parent = tables.ManyToManyColumn(verbose_name="Parents")
|
||||
|
||||
class Meta:
|
||||
class Meta(SelectionTable.Meta):
|
||||
model = Examination
|
||||
template_name = "django_tables2/bootstrap4.html"
|
||||
#fields = ("primary", "subspecialty")
|
||||
sequence = ("examination",)
|
||||
|
||||
class SupervisorTable(tables.Table):
|
||||
class SupervisorTable(SelectionTable):
|
||||
name = tables.Column(
|
||||
linkify=("generic:supervisor_detail", {"pk": tables.A("pk")}),
|
||||
verbose_name="Name",
|
||||
@@ -383,13 +383,13 @@ class SupervisorTable(tables.Table):
|
||||
accessor="pk", orderable=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
class Meta(SelectionTable.Meta):
|
||||
model = Supervisor
|
||||
template_name = "django_tables2/bootstrap4.html"
|
||||
|
||||
sequence = ("name", "email")
|
||||
exclude = ("id",)
|
||||
attrs = {"id": "supervisor-table"}
|
||||
SelectionTable.Meta.attrs.update({"id": "supervisor-table"})
|
||||
|
||||
def render_edit(self, value, record):
|
||||
url = f"{reverse("generic:supervisor_edit", args=[record.pk])}?redirect={self.request.path}"
|
||||
|
||||
@@ -7,23 +7,12 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="view-filter-options">
|
||||
<details class="filter">
|
||||
<summary>
|
||||
<h3>Filter CID Users </h3>
|
||||
</summary>
|
||||
<form action="" method="get">
|
||||
{{ filter.form |crispy}}
|
||||
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span id="manage-span">
|
||||
{% render_table table %}
|
||||
</span>
|
||||
</div>
|
||||
{% include "generic/partials/filter_bar.html" with filter=filter app_name=app_name collapse_id="bottom-filter-body" %}
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
|
||||
@@ -4,18 +4,6 @@
|
||||
|
||||
<h2>Supervisors</h2>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h4>Filter</h4>
|
||||
</summary>
|
||||
<div id="view-filter-options">
|
||||
<form action="" method="get">
|
||||
{{ filter.form }}
|
||||
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{% render_table table %}
|
||||
|
||||
{% comment %} <ul id="supervisor-list">
|
||||
@@ -25,6 +13,7 @@
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul> {% endcomment %}
|
||||
{% include "generic/partials/filter_bar.html" with filter=filter app_name=app_name collapse_id="bottom-filter-body" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
{% render_table table %}
|
||||
</span>
|
||||
</div>
|
||||
{% include "generic/partials/filter_bar.html" with filter=filter app_name=app_name collapse_id="bottom-filter-body" %}
|
||||
|
||||
<a href="{% url 'accounts_bulk_create' %}">Bulk create users</a>
|
||||
<a href="{% url 'create_user' %}">Create single user</a>
|
||||
|
||||
Reference in New Issue
Block a user