Skip to content

Instantly share code, notes, and snippets.

View jurrian's full-sized avatar

Jurrian Tromp jurrian

View GitHub Profile
@jurrian
jurrian / admin.py
Created February 7, 2024 11:16
FilterColumnsMixin for adding a button for selecting which columns to show in Django admin changelist
from app.forms import FilterColumnsForm
from django.contrib.admin.utils import label_for_field
from django.template.response import TemplateResponse
from django.urls import path
from django.utils.translation import gettext_lazy as _
class FilterColumnsMixin:
"""Allow users to filter the columns in the changelist.
This will add a "Columns" button to the changelist page to select the columns to display.
@jurrian
jurrian / expiring_superuser.py
Last active September 4, 2023 12:23
Mixin to apply over the Django `User` or `AbstractUser` model, this will change the superuser checkbox to a datetime field that will expire.
from datetime import timedelta
from django.db import models
from django.utils.timezone import now
class ExpiringSuperuserMixin:
_is_superuser = models.DateTimeField(
_('superuser until'),
blank=True,
@jurrian
jurrian / currency_serializerfield.py
Created July 21, 2023 12:14
CurrencySerializerField for serializing CurrencyField in Django Rest Framework
class CurrencySerializerField(DecimalField):
"""Serialize CurrencyField with 2 decimal places for presentation, keep 4 decimals for internal.
This is implemented by BaseSerializer.
Cannot just set `decimal_places=2` since it will error on input validation when 4 decimals.
For rounding we use "bankers rounding", this is the most common practise but local law can differ.
"""
def __init__(self, *args, max_digits=None, decimal_places=None, **kwargs):
"""Some values are hard coded as they are supposed to be the same for all.
@jurrian
jurrian / currency_field.py
Created July 21, 2023 11:59
CurrencyField for Django to enforce accuracy for monetary amounts
class CurrencyField(DecimalField):
"""Special DecimalField with defaults for currency.
Currency should be stored in the database with 4 decimal places so any calculations will not have rounding errors.
Formfields will use 4 decimal places to avoid rounding errors. Any other display of currency fields uses 2 decimals.
All fields that process currency should use this field, especially when used in calculations.
"""
display_decimals = 2 # Representation decimals
db_decimals = 4 # Database storage decimals
max_digits = 10
@jurrian
jurrian / change_list.html
Last active April 24, 2023 12:59
Django Simple History for list pages
{# file: templates/admin/change_list.html #}
{% extends 'admin/change_list.html' %}
{% load i18n admin_urls %}
{% block object-tools-items %}
{% if cl.pk_attname != 'history_id' %}
<li>
{% url opts|admin_urlname:'changelist_history' as history_url %}
<a href="{% add_preserved_filters history_url %}" class="historylink">{% translate "History" %}</a>
@jurrian
jurrian / jwt_auth.py
Created March 13, 2023 12:29
JWT authentication implementation for python requests
import time
from json import JSONDecodeError
from typing import Dict
import requests
from requests import PreparedRequest, RequestException
from requests.auth import AuthBase
REQUEST_TIMEOUT = 30 # Seconds
@jurrian
jurrian / diffmixin.py
Last active January 30, 2023 11:45
DiffMixin for Django models
class DiffMixin:
"""Detect changes on a model instance after saving or deleting.
The original will be retrieved from the db, so any unrelated added attributes are not taken into account.
It uses save() and delete() as "hooks", but can also be triggered manually using copy_original():
```
class SomeModel(DiffMixin, models.Model):
some_attribute = models.IntegerField()
@jurrian
jurrian / raw_id_widget.py
Last active January 11, 2023 14:56
Patched ForeignKeyRawIdWidget for prefetching
from django.contrib.admin import widgets
from django.contrib.admin.options import get_ul_class
from django.contrib.admin.widgets import AutocompleteSelect
from django.forms import boundfield, models
from django.urls import reverse
from django.urls.exceptions import NoReverseMatch
from django.utils.text import Truncator
from django.utils.translation import gettext_lazy as _
@jurrian
jurrian / settings.py
Created September 30, 2021 10:20
Client-side rate limiting for Sentry
import logging
import sentry_sdk
from ratelimitingfilter import RateLimitingFilter
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.logging import LoggingIntegration
# Sentry
sentry_logging = LoggingIntegration(
level=logging.INFO, # Capture info and above as breadcrumbs