[Fixed]-How to add custom page to django admin with custom form, not related to any Model?

7👍

Using a proxy model would save some typing:

class ImportCSVData(SomeModel):
    class Meta:
        proxy = True

@admin.register(ImportCSVData)
class MyCustomAdminForm(admin.ModelAdmin):
    ... as in accepted answer ...
👤mrts

7👍

I found a snippet for this situation

from django.contrib import admin, messages
from django.http import HttpResponseRedirect
from django.shortcuts import render

from my_app.forms import CustomForm


class FakeModel(object):
    class _meta:
        app_label = 'my_app'  # This is the app that the form will exist under
        model_name = 'custom-form'  # This is what will be used in the link url
        verbose_name_plural = 'Custom AdminForm'  # This is the name used in the link text
        object_name = 'ObjectName'

        swapped = False
        abstract = False


class MyCustomAdminForm(admin.ModelAdmin):
    """
    This is a funky way to register a regular view with the Django Admin.
    """

    def has_add_permission(*args, **kwargs):
        return False

    def has_change_permission(*args, **kwargs):
        return True

    def has_delete_permission(*args, **kwargs):
        return False

    def changelist_view(self, request):
        context = {'title': 'My Custom AdminForm'}
        if request.method == 'POST':
            form = CustomForm(request.POST)
            if form.is_valid():
                # Do your magic with the completed form data.

                # Let the user know that form was submitted.
                messages.success(request, 'Congrats, form submitted!')
                return HttpResponseRedirect('')
            else:
                messages.error(
                    request, 'Please correct the error below'
                )

        else:
            form = CustomForm()

        context['form'] = form
        return render(request, 'admin/change_form.html', context)


admin.site.register([FakeModel], MyCustomAdminForm)

from django import forms


class CustomForm(forms.Form):

# Your run-of-the-mill form here

1👍

I’m glad to say that since version 1.3.0 django-etc ships with etc.admin.CustomModelPage. So you may want to do something like:

    from etc.admin import CustomModelPage

    class BulkPage(CustomModelPage):
    
        title = 'Test page 1'  # set page title

        # Define some fields.
        my_field = models.CharField('some title', max_length=10)

        def save(self):
            # Here implement bulk creation using values 
            # from self fields attributes, e.g. self.my_field.
            super().save()

    # Register this page within Django admin.
    BulkPage.register()

0👍

When I came across this answer, I was hoping to find a way to add a second form to the admin page for an existing model. The answer here gets you sort of close, but there is a much easier way to approach this.

For this example, I will assume the model we’re working with is called Candle.

# Make a proxy class for your model, since
# there can only be one admin view per model.
class EasyCandle(models.Candle):
    class Meta:
        proxy = True

# Make a ModelAdmin for your proxy class.
@admin.register(EasyCandle)
class EasyCandleAdminForm(admin.ModelAdmin):
    # In my case, I only want to use it for adding a new model.
    # For changing an existing instance of my model or deleting
    # an instance of my model, I want to just use the
    # views already available for the existing model.
    # So has_add_permission returns True while the rest return False.
    def has_add_permission(*args, **kwargs):
        return True

    def has_change_permission(*args, **kwargs):
        return False

    def has_delete_permission(*args, **kwargs):
        return False

    # This replaces all the complicated stuff other
    # answers do with changelist_view. 
    def get_form(self, request, obj=None, **kwargs):
        return EasyCandleForm


# Finally, make whatever form you want.
# In this case, I exclude some fields and add new fields.
class EasyCandleForm(forms.ModelForm):
    class Meta:
        model = models.Candle
        # Note, do NOT exclude fields when you want to replace their form fields.
        # If you do that, they don't get persisted to the DB.
        fields = "__all__"

    vessel = forms.CharField(
        required=True,
        help_text="If the vessel doesn't already exist in the DB, it will be added for you",
    )

Leave a comment