Skip to content

Instantly share code, notes, and snippets.

@Tobi-De
Last active July 6, 2023 11:07
Show Gist options
  • Save Tobi-De/05e76ac3503a2776cf95115f9b49811f to your computer and use it in GitHub Desktop.
Save Tobi-De/05e76ac3503a2776cf95115f9b49811f to your computer and use it in GitHub Desktop.
Some django utils I usually have in my projects
# render pdf using weasyprint
# depends on: weasyprint
import weasyprint
from django.template.loader import render_to_string
def render_to_pdf(template_src, context_dict=None):
html = render_to_string(template_src, context_dict)
try:
pdf = weasyprint.HTML(string=html).write_pdf()
except Exception as e:
logger.error(f"Pdf rendering: {e}")
return None
return pdf
# qosic mobile money payment client
# depends on: qosic-sdk
QOSIC = {
"moov_id": env("MOOV_CLIENT_ID"),
"mtn_id": env("MTN_CLIENT_ID"),
"login": env("QOSIC_SERVER_LOGIN"),
"password": env("QOSIC_SERVER_PASS"),
}
from django.conf import settings
from qosic import Client, MtnConfig, MTN, MOOV
def get_qosic_client() -> Client:
providers = [
MTN(
client_id=settings.QOSIC.get("mtn_id"),
config=MtnConfig(step=30, timeout=60 * 2),
),
MOOV(client_id=settings.QOSIC.get("moov_id")),
]
return Client(
providers=providers,
login=settings.QOSIC.get("login").strip(),
password=settings.QOSIC.get("password").strip(),
)
# add a filtered table in a function view context data
# depends on: django-filter, django-tables2
from typing import Any, Type
import django_filters as filters
import django_tables2 as table
def paginated_table_context_data(
queryset: QuerySet,
*,
request: HttpRequest,
table_class: Type[tables.Table],
filter_class: Optional[Type[filters.FilterSet]] = None,
paginage_by: int = 10,
) -> dict[str, Any]:
context = {}
if filter_class:
context["filter"] = filter_class(request.GET)
filterset = filter_class(request.GET, queryset=queryset)
if filterset.is_bound or filterset.is_valid():
qs = filterset.qs
else:
qs = filterset.queryset.none()
else:
qs = queryset
table = table_class(data=qs, request=request)
page_number = int(request.GET.get("page", 1))
table = table.paginate(page=page_number, per_page=paginage_by)
context["table"] = table
return context
# htmx decorator for function based views
# depends on: django-htmx
from functools import wraps
def htmx_view(full_template: str, partial_template: str):
def inner(view):
@wraps(view)
def func(request, *args, **kwargs):
context: dict = view(request, *args, **kwargs)
template = partial_template if request.htmx else full_template
return TemplateResponse(request, template, context)
return func
return inner
# file upload_to
def user_upload_to(instance: Any, filename: str, category: str):
return f"users/{instance.id}/{category}/{filename}"
# lazily evaluate context processor data, this trick can be used with any data anywhere
from functools import lru_cache
def my_context_processor(request):
@lru_cache()
def complicated_query():
result = do_stuff()
return result
return {'my_info': complicated_query}
# view decorator
def require(methods=("GET", "POST"), login=True):
def decorator(func):
wrapped = func
if methods is not None:
wrapped = require_http_methods(methods)(func)
if login:
wrapped = login_required(func)
return wrapped
return decorator
# return html for django-tables column
def render_actions(self, value: str, **kwargs):
html = (
TemplateResponse(
request=self.request,
template="customers/partials/delete_button.html",
context={"delete_url": value},
)
.render()
.rendered_content
)
return mark_safe(html)
# load data into tablib from django.core.files.File
def import_from_file(cls, file: File) -> list | None:
filename, extension = os.path.splitext(file.name)
file_format = extension[1:]
if file_format in ["xls", "xlsx"]:
databook = tablib.Databook().load(file.read(), format=file_format)
dataset = databook.sheets()[0]
else:
dataset = tablib.Dataset().load(
file.read().decode("utf-8"), format=file_format
)
result = cls().import_data(
dataset=dataset,
use_transactions=True,
rollback_on_validation_errors=True,
collect_failed_rows=True,
)
if result.has_errors():
return result.row_errors()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment