Source code for coffee.contrib.render.functions
import re
from importlib import import_module
from inspect import getmembers, isclass
from django.urls import reverse
from coffee.exceptions import DefinitionNotFound, FieldNotSupported
from coffee.contrib.render.components import (
CSRFToken,
Form,
Input,
Pagination,
SubmitButton,
TBody,
THead,
TRow,
Table,
Td,
Th,
)
from coffee.contrib.render.definitions import (
FORM_TRANSLATION,
)
from django.db.models.base import ModelBase
from django.forms.models import model_to_dict
from django.middleware.csrf import get_token
[docs]def get_model_definitions(app_name):
module = import_module(f"{app_name}.models")
models = getmembers(module, predicate=isclass)
definitions = {}
for model_name, model in models:
if type(model) == ModelBase and hasattr(model, "_meta"):
rx = re.compile(r"(?:<class [\"'])(.+)(?:[\"']>)")
match = rx.findall(repr(model))
match = match[0].split(".")[0]
if match == app_name:
if model_name not in definitions:
definitions[model_name] = {}
for field in model._meta.fields:
related_model = None
if field.related_model:
related_model = field.related_model.__name__
definitions[model_name][field.name] = {
"related_model": related_model,
"primary_key": field.primary_key,
"db_type": field.get_internal_type(),
"nullable": field.null,
}
return definitions
[docs]def get_input_template(field):
db_type = field.get("db_type")
if db_type not in FORM_TRANSLATION:
raise FieldNotSupported()
template = FORM_TRANSLATION[db_type]
return template
[docs]def get_csrf_token(request):
csrf_token = get_token(request)
return CSRFToken(value=csrf_token)
[docs]def render_model_form(request, app_name, model_name, instance, form_only=None):
definitions = get_model_definitions(app_name)
if model_name not in definitions:
raise DefinitionNotFound(model_name)
definition = definitions[model_name]
base_url = reverse("coffee_post")
action = base_url + f"?app_name={app_name}&model_name={model_name}"
children = []
for name, field in definition.items():
template = get_input_template(field)
primary_key = field.get("primary_key")
if field.get("related_model"):
name = name + "_id"
if template.implemented is True and not primary_key:
value = getattr(instance, name, None)
item = Input(field_name=name, template=template, value=value)
children.append(item)
children.append(get_csrf_token(request))
if not form_only:
button_text = "Submit"
if instance:
button_text = "Update"
children.append(SubmitButton(value=button_text))
form = Form(children=children, action=action)
html = str(form)
delete_button = ""
if not form_only:
if instance:
delete_button = get_delete_button_html(
request=request,
app_name=app_name,
model_name=model_name,
pk=instance.pk,
)
html += str(delete_button)
return html
[docs]def render_model_table(cls, queryset, pagination):
keys = [i.name for i in cls._meta.fields]
headers = [Th(i) for i in keys]
thead = THead(value=TRow(children=headers, pk=None))
trs = []
for row in queryset:
row_dict = model_to_dict(row)
tds = []
for key in keys:
tds.append(Td(value=row_dict.get(key)))
trs.append(TRow(children=tds, pk=row.pk))
tbody = TBody(children=trs)
html = str(Table(tbody=tbody, thead=thead))
if pagination:
pagination_html = Pagination(pagination=pagination)
html += str(pagination_html)
return html
[docs]def get_delete_button_html(request, app_name, model_name, pk):
base_url = reverse("coffee_delete")
action = base_url + f"?app_name={app_name}&model_name={model_name}&pk={pk}"
children = [get_csrf_token(request), SubmitButton(value="Delete")]
form = Form(action=action, children=children)
return form