support view logic on HTML side
Some checks failed
Lint / lint (push) Has been cancelled

This commit is contained in:
jpt 2025-05-03 22:22:41 -05:00
parent 87b8c3894e
commit 97aeace80a
6 changed files with 118 additions and 2 deletions

View File

@ -3,7 +3,7 @@ from ninja import Schema
from ninja.security import APIKeyQuery
import datetime
from ..accounts.models import User
from .models import ThingEdit, Thing as ThingModel
from .models import ThingEdit, Thing as ThingModel, View as ViewModel
class ApiKey(APIKeyQuery):
@ -21,12 +21,31 @@ class ApiKey(APIKeyQuery):
api = NinjaAPI(auth=ApiKey())
class View(Schema):
name: str
columns: dict
filters: dict
sort: str
class Thing(Schema):
id: int
data: dict
type: str
@api.post("/view/")
def sync_view(request, view: View):
ViewModel.objects.update_or_create(
name=view.name,
defaults=dict(
columns=view.columns,
filters=view.filters,
sort=view.sort,
),
)
@api.post("/thing/")
def sync_thing(request, thing: Thing):
action = "none"

View File

@ -0,0 +1,32 @@
# Generated by Django 5.2 on 2025-05-04 02:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("core", "0003_alter_thing_created_at"),
]
operations = [
migrations.CreateModel(
name="View",
fields=[
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("name", models.CharField(max_length=100)),
("columns", models.JSONField()),
("filters", models.JSONField()),
("sort", models.CharField()),
],
),
migrations.AlterField(
model_name="thing",
name="deleted",
field=models.BooleanField(default=False),
),
]

View File

@ -2,6 +2,13 @@ from django.db import models
from ..accounts.models import User
class View(models.Model):
name = models.CharField(max_length=100)
columns = models.JSONField()
filters = models.JSONField()
sort = models.CharField()
class Thing(models.Model):
thing_id = models.PositiveIntegerField()
user = models.ForeignKey(User, related_name="things", on_delete=models.CASCADE)

View File

@ -1,3 +1,39 @@
from django.shortcuts import render
from ..accounts.models import User
from .models import Thing, View
# Create your views here.
def attr_then_dict(thing, field):
try:
return getattr(thing, field)
except AttributeError:
return thing.data.get(field, "")
def thing_to_row(view, thing):
"""convert one thing to corresponding row dict"""
return [attr_then_dict(thing, col["field_name"]) for col in view.columns.values()]
def table(request):
token = request.GET.get("token")
view_name = request.GET.get("view")
user = User.objects.get(username=token)
view = View.objects.get(name=view_name)
things = Thing.objects.filter(user=user, deleted=False)
for field, val in view.filters.items():
if field == "type":
things = things.filter(type=val)
else:
val = val.split(",")
if len(val) == 1:
things = things.filter(**{f"data__{field}": val})
else:
things = things.filter(**{f"data__{field}__in": val})
things = things.order_by(*[f"data__{sort}" for sort in view.sort.split(",")])
# execute query
rows = (thing_to_row(view, thing) for thing in things)
return render(request, "thingtable.html", {"rows": rows, "view": view})

View File

@ -3,11 +3,13 @@ from django.contrib import admin
from django.urls import path, include
from debug_toolbar.toolbar import debug_toolbar_urls
from apps.core.api import api
from apps.core import views
urlpatterns = [
path("djadmin/", admin.site.urls),
path("accounts/", include("allauth.urls")),
path("api/", api.urls),
path("table/", views.table),
]
if settings.DEBUG and not settings.IS_TESTING:

20
templates/thingtable.html Normal file
View File

@ -0,0 +1,20 @@
<table>
<thead>
<tr>
{% for col in view.columns %}
<th>{{ col }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
{% for item in row %}
<td>
{{ item }}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>