Author SHA1 Message Date
Eden Kirin 382e514d03 City as select 2024-05-16 21:40:28 +02:00
Eden Kirin fc6b3a7fa0 Validation 2024-05-16 07:55:27 +02:00
Eden Kirin 2fc2d07a7d Persons constraint 2024-05-16 07:35:01 +02:00
Eden Kirin 178377cfb6 Finished 2024-05-15 22:56:30 +02:00
7 changed files with 198 additions and 55 deletions
Binary file not shown.
@@ -0,0 +1,46 @@
# 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),
],
),
),
]
+19 -3
View File
@@ -1,10 +1,26 @@
from django.core.validators import MaxLengthValidator, MinLengthValidator
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
city = models.CharField(max_length=100)
name = models.CharField(
max_length=100,
blank=False,
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:
db_table = "persons"
@@ -1,43 +1,78 @@
{% macro inline_table_row(person, is_editing) %}
{% macro inline_table_row(person) %}
<tr hx-target="this" hx-swap="outerHTML">
{% if is_editing %}
<td>
<input class="form-control" name="name" value="{{ person.name }}">
</td>
<td>
<input class="form-control" name="address" value="{{ person.address }}">
</td>
<td>
<input class="form-control" name="city" value="{{ person.city }}">
</td>
<td>
<button
class="btn btn-outline-success"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
hx-vals='{"action": "save"}'
>
<i class="bi bi-check-circle-fill"></i>
</button>
<button
class="btn btn-outline-danger"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
hx-vals='{"action": "cancel"}'
>
<i class="bi bi-x-circle-fill"></i>
</button>
</td>
{% else %}
<td>{{ person.name }}</td>
<td>{{ person.address }}</td>
<td>{{ person.city }}</td>
<td>
<button
class="btn btn-outline-primary"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
>
<i class="bi bi-pencil-square"></i>
</button>
</td>
{% endif %}
<td>{{ person.name }}</td>
<td>{{ person.address }}</td>
<td>{{ person.city }}</td>
<td>
<button
class="btn btn-outline-primary"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
>
<i class="bi bi-pencil-square"></i>
</button>
</td>
</tr>
{% endmacro %}
{% macro inline_table_row_edit(person, cities, errors={}) %}
{% macro render_input(field_name, value) %}
{% set has_error = field_name in errors %}
<input
class="form-control {% if has_error %}is-invalid{% endif %}"
name="{{ field_name }}"
value="{{ value }}"
{% if has_error %}title="{{ errors[field_name] }}"{% endif %}
>
{% endmacro %}
{% macro render_select(field_name, value, options) %}
{% set has_error = field_name in errors %}
<select
class="form-select {% if has_error %}is-invalid{% endif %}"
name="{{ field_name }}"
{% if has_error %}title="{{ errors[field_name] }}"{% endif %}
>
{% for option in options %}
{% set selected = value == option %}
<option value="{{ option }}" {% if selected %}selected{% endif %}>
{{ option }}
</option>
{% endfor %}
</select>
{% endmacro %}
<tr
id="person-row-{{ person.pk }}"
hx-target="this"
hx-swap="outerHTML"
>
<td>
{{ render_input(field_name="name", value=person.name) }}
</td>
<td>
{{ render_input(field_name="address", value=person.address) }}
</td>
<td>
{# {{ render_input(field_name="city", value=person.city) }}#}
{{ render_select(field_name="city", value=person.city, options=cities) }}
</td>
<td>
<button
class="btn btn-outline-success"
hx-post="{{ url("table-inline-edit-row", pk=person.pk) }}"
hx-include="#person-row-{{ person.pk }} input, #person-row-{{ person.pk }} select"
>
<i class="bi bi-check-circle-fill"></i>
</button>
<button
class="btn btn-outline-danger"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
hx-vals='{"action": "cancel"}'
>
<i class="bi bi-x-circle-fill"></i>
</button>
</td>
</tr>
{% endmacro %}
@@ -17,7 +17,7 @@
</thead>
<tbody>
{% for person in persons %}
{{ inline_table_row(person, is_editing=False) }}
{{ inline_table_row(person) }}
{% endfor %}
</tbody>
</table>
@@ -1,3 +1,7 @@
{% 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_edit %}
{{ inline_table_row(person, is_editing=is_editing) }}
{% if is_editing %}
{{ inline_table_row_edit(person, cities=cities, errors=errors) }}
{% else %}
{{ inline_table_row(person) }}
{% endif %}
+51 -9
View File
@@ -1,10 +1,29 @@
from typing import Any
from typing import Any, Optional
from django.http import Http404
from django.core.exceptions import ValidationError
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.views.demo_view_base import DemoViewBase
CITIES: list[str] = [
"",
"Zagreb",
"Split",
"Pula",
"Rijeka",
"Kozari bok",
]
def get_person(pk: int) -> Person:
try:
return Person.objects.get(pk=pk)
except Person.DoesNotExist:
raise Http404("Person not found")
class TableInlineEditView(DemoViewBase):
template_name = "main/table_inline_edit.html"
@@ -30,17 +49,40 @@ class TableInlineEditRowView(DemoViewBase):
def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs)
try:
person = Person.objects.get(pk=kwargs.get("pk"))
except Person.DoesNotExist:
raise Http404("Person not found")
action = self.request.GET.get("action")
person = get_person(pk=kwargs.get("pk"))
action = self.request.GET.get("action", "edit")
context_data.update(
{
"person": person,
"is_editing": action != "cancel",
"cities": CITIES,
"is_editing": action == "edit",
}
)
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()
return render(
context={
"person": person,
"errors": errors,
"cities": CITIES,
"is_editing": errors is not None,
},
template_name=self.template_name,
request=request,
)