1 Commits

Author SHA1 Message Date
c7f89a9ab4 Basic table inline edit functionality 2024-05-15 22:15:27 +02:00
7 changed files with 25 additions and 133 deletions

View File

@ -13,7 +13,7 @@ class MainConfig(AppConfig):
"""copy template database if db not exists""" """copy template database if db not exists"""
db_fname = settings.DATABASES["default"]["NAME"] db_fname = settings.DATABASES["default"]["NAME"]
template_db_fname = settings.BASE_DIR / "db.template.sqlite3" template_db_fname = settings.BASE_DIR / "db_template.sqlite3"
if os.path.exists(db_fname): if os.path.exists(db_fname):
return return

View File

@ -1,46 +0,0 @@
# Generated by Django 5.0.4 on 2024-05-16 05:33
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("main", "0003_person"),
]
operations = [
migrations.AlterField(
model_name="person",
name="address",
field=models.CharField(
max_length=100,
validators=[
django.core.validators.MinLengthValidator(2),
django.core.validators.MaxLengthValidator(100),
],
),
),
migrations.AlterField(
model_name="person",
name="city",
field=models.CharField(
max_length=100,
validators=[
django.core.validators.MinLengthValidator(2),
django.core.validators.MaxLengthValidator(100),
],
),
),
migrations.AlterField(
model_name="person",
name="name",
field=models.CharField(
max_length=100,
validators=[
django.core.validators.MinLengthValidator(2),
django.core.validators.MaxLengthValidator(100),
],
),
),
]

View File

@ -1,26 +1,10 @@
from django.core.validators import MaxLengthValidator, MinLengthValidator
from django.db import models from django.db import models
class Person(models.Model): class Person(models.Model):
name = models.CharField( name = models.CharField(max_length=100)
max_length=100, address = models.CharField(max_length=100)
blank=False, city = models.CharField(max_length=100)
null=False,
validators=[MinLengthValidator(2), MaxLengthValidator(100)],
)
address = models.CharField(
max_length=100,
blank=False,
null=False,
validators=[MinLengthValidator(2), MaxLengthValidator(100)],
)
city = models.CharField(
max_length=100,
blank=False,
null=False,
validators=[MinLengthValidator(2), MaxLengthValidator(100)],
)
class Meta: class Meta:
db_table = "persons" db_table = "persons"

View File

@ -1,30 +1,20 @@
{% macro inline_table_row(person, is_editing, errors={}) %} {% macro inline_table_row(person, is_editing) %}
{% macro render_input(field_name, value) %} <tr hx-target="this" hx-swap="outerHTML">
{% set has_error = field_name in errors %} {% if is_editing %}
<input
class="form-control {% if has_error %}is-invalid{% endif %}"
name="{{ field_name }}"
value="{{ value }}"
{% if has_error %}title="{{ errors[field_name] }}"{% endif %}
>
{% endmacro %}
{% if is_editing %}
<tr id="person-row-{{ person.pk }}" hx-target="this" hx-swap="outerHTML">
<td> <td>
{{ render_input(field_name="name", value=person.name) }} <input class="form-control" name="name" value="{{ person.name }}">
</td> </td>
<td> <td>
{{ render_input(field_name="address", value=person.address) }} <input class="form-control" name="address" value="{{ person.address }}">
</td> </td>
<td> <td>
{{ render_input(field_name="city", value=person.city) }} <input class="form-control" name="city" value="{{ person.city }}">
</td> </td>
<td> <td>
<button <button
class="btn btn-outline-success" class="btn btn-outline-success"
hx-post="{{ url("table-inline-edit-row", pk=person.pk) }}" hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
hx-include="#person-row-{{ person.pk }} input" hx-vals='{"action": "save"}'
> >
<i class="bi bi-check-circle-fill"></i> <i class="bi bi-check-circle-fill"></i>
</button> </button>
@ -36,9 +26,7 @@
<i class="bi bi-x-circle-fill"></i> <i class="bi bi-x-circle-fill"></i>
</button> </button>
</td> </td>
</tr> {% else %}
{% else %}
<tr hx-target="this" hx-swap="outerHTML">
<td>{{ person.name }}</td> <td>{{ person.name }}</td>
<td>{{ person.address }}</td> <td>{{ person.address }}</td>
<td>{{ person.city }}</td> <td>{{ person.city }}</td>
@ -46,11 +34,10 @@
<button <button
class="btn btn-outline-primary" class="btn btn-outline-primary"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}" hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
> >
<i class="bi bi-pencil-square"></i> <i class="bi bi-pencil-square"></i>
</button> </button>
</td> </td>
</tr> {% endif %}
{% endif %} </tr>
{% endmacro %} {% endmacro %}

View File

@ -1,3 +1,3 @@
{% from "main/components/inline_table_row.html" import inline_table_row %} {% from "main/components/inline_table_row.html" import inline_table_row %}
{{ inline_table_row(person, is_editing=is_editing, errors=errors) }} {{ inline_table_row(person, is_editing=is_editing) }}

View File

@ -1,21 +1,11 @@
from typing import Any, Optional from typing import Any
from django.core.exceptions import ValidationError from django.http import Http404
from django.core.handlers.wsgi import WSGIRequest
from django.http import Http404, HttpResponse
from django.shortcuts import render
from project.main.models import Person from project.main.models import Person
from project.main.views.demo_view_base import DemoViewBase from project.main.views.demo_view_base import DemoViewBase
def get_person(pk: int) -> Person:
try:
return Person.objects.get(pk=pk)
except Person.DoesNotExist:
raise Http404("Person not found")
class TableInlineEditView(DemoViewBase): class TableInlineEditView(DemoViewBase):
template_name = "main/table_inline_edit.html" template_name = "main/table_inline_edit.html"
active_section = "table-inline-edit" active_section = "table-inline-edit"
@ -40,40 +30,17 @@ class TableInlineEditRowView(DemoViewBase):
def get_context_data(self, **kwargs) -> dict[str, Any]: def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs) context_data = super().get_context_data(**kwargs)
person = get_person(pk=kwargs.get("pk")) try:
action = self.request.GET.get("action", "edit") person = Person.objects.get(pk=kwargs.get("pk"))
except Person.DoesNotExist:
raise Http404("Person not found")
action = self.request.GET.get("action")
context_data.update( context_data.update(
{ {
"person": person, "person": person,
"is_editing": action == "edit", "is_editing": action != "cancel",
} }
) )
return context_data return context_data
def post(self, request: WSGIRequest, *args, **kwargs) -> HttpResponse:
errors: Optional[dict[str, str]] = None
person = get_person(pk=kwargs.get("pk"))
person.name = request.POST.get("name")
person.address = request.POST.get("address")
person.city = request.POST.get("city")
try:
person.clean_fields()
except ValidationError as ex:
errors = {key: value[0].message for key, value in ex.error_dict.items()}
else:
person.save()
print(errors)
return render(
context={
"person": person,
"errors": errors,
"is_editing": errors is not None,
},
template_name=self.template_name,
request=request,
)