I have a Django application which handles license codes, so there’s a model and a modeladmin, and that all works. But I want to add a custom page to the admin interface to generate a whole bunch of license codes and while everything is working, it looks really bad.
So first of all to get a new button in the top right, I have a custom change_list.html
template for this specific model:
{% extends "admin/change_list.html" %}
{% block object-tools-items %}
{{ block.super }}
<li><a href="generate/" class="addlink">Generate Codes</a></li>
{% endblock %}
This makes the extra button show up in the top right of the list of items. Clicking on that button opens a new page, which I created with this code:
@admin.register(RedeemCode)
class RedeemCodeAdmin(admin.ModelAdmin):
# [...the usual admin config...]
def get_urls(self):
return [
path("generate/", self.admin_site.admin_view(self.generate_codes), name="generate-codes"),
] + super().get_urls()
def generate_codes(self, request):
class GenerateCodeForm(forms.Form):
product = forms.ModelChoiceField(queryset=ProductVariant.objects.all())
partner = forms.ModelChoiceField(queryset=Partner.objects.all())
comment = forms.CharField()
count = forms.IntegerField(min_value=1, initial=1)
for_email = forms.CharField()
export_csv = forms.BooleanField(required=False, label="Export generated codes to CSV")
if request.method == "POST":
form = GenerateCodeForm(request.POST)
if form.is_valid():
print(form.cleaned_data)
return HttpResponseRedirect("/admin/shop/redeemcode/")
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
opts=RedeemCode._meta,
title="Generate Codes",
form=GenerateCodeForm(),
)
return TemplateResponse(request, "admin/shop/redeemcode/generate_codes.html", context)
And my generate_codes.html
template:
{% extends "admin/base_site.html" %}
{% load i18n admin_urls %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
› <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
› <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
› {% translate 'Generate Codes' %}
</div>
{% endblock %}
{% block content %}
<form action="." method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Generate codes">
</form>
{% endblock %}
The result looks like this:
It all works perfectly fine but that’s not very good looking. Compared to normal add/edit admin forms the labels don’t line up, text input fields are a lot smaller, the checkbox label is shown in front instead of after the checkbox, there’s no padding between the form and the submit button, etc.
So the question is how I can reuse the admin look and feel for a custom form on a custom page.