Pass parameters in URL to Django Admin add_view
Question:
I need to pass a parameter in the URL to the Django Admin add
view, so that when I type the URL: http://localhost:8000/admin/myapp/car/add?brand_id=1
, the add_view
reads the brand_id
parameter. I want to use this so that I can set a default value for the brand
attribute of Car
.
def get_form(self, request, obj=None, **kwargs):
form = super(CarAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['brand'].initial = <<GET['brand_id']>>
return form
Use case: I want this because in my BrandsAdmin
, I have added a "+" button for each brand, that should add a Car
with that Brand
as FK.
I’ve tried getting it from request
in get_form
, but when that code is executed, Django has already changed my URL as I guess it doesn’t understand it as a "legal" parameter.
Thanks a lot!
Answers:
You can find a full explanation here, but shortly:
You can access query parameters directly from the view, the request object has a method. I suppose it is a GET request, so an example for your implementation would be:
request.GET.getlist("brand_id")
or
request.GET.get("brand_id")
Mainly, for what I wanted to do, it’s as easy as two steps.
First, add a column in list_display
to show the link to the add_view
:
Brand.py
@admin.display(description='Link', ordering='url')
def get_add_link(self):
url = f"{reverse('admin:myapp_car_add')}?brand={self.id}"
return format_html(f"<a href='{url}'><i class='fas fa-plus'></i></a>")
Note that I add the URL as the reverse of admin:<app>_<model>_<action>
and pass the brand ID as parameter.
CarAdmin.py
def get_changeform_initial_data(self, request):
brand_id = request.GET.get('brand')
return {'brand': brand_id}
By adding this method in the CarAdmin
class, I am able to set the brand as the default value.
Using django 3 i did it overriding get_form in CarAdmin.py like you did, and its working for me, maybe the trick is in Brand.py:
Brand.py
readonly_fields = ('get_add_link',)
def get_add_link(self, obj):
url = f"{reverse('admin:myapp_car_add')}?brand={self.id}"
return format_html(f"<a href='{url}'><i class='fas fa-plus'></i></a>")
CarAdmin.py
def get_form(self, request, obj=None, **kwargs):
form = super(CarAdmin, self).get_form(request, obj, **kwargs)
brand_id = request.GET.get('brand')
if brand_id and len(brand_id) > 0:
form.base_fields['brand'].initial = brand_id
I did not have to do anything with the Model
. The only change needed was in the ModelAdmin
:
def get_changeform_initial_data(self, request):
brand = None
brand_id = request.GET.get('brand')
if (brand_id):
brand = Brand.objects.get(id=brand_id)
return {'brand': brand}
Docs link here: https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_changeform_initial_data
I need to pass a parameter in the URL to the Django Admin add
view, so that when I type the URL: http://localhost:8000/admin/myapp/car/add?brand_id=1
, the add_view
reads the brand_id
parameter. I want to use this so that I can set a default value for the brand
attribute of Car
.
def get_form(self, request, obj=None, **kwargs):
form = super(CarAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['brand'].initial = <<GET['brand_id']>>
return form
Use case: I want this because in my BrandsAdmin
, I have added a "+" button for each brand, that should add a Car
with that Brand
as FK.
I’ve tried getting it from request
in get_form
, but when that code is executed, Django has already changed my URL as I guess it doesn’t understand it as a "legal" parameter.
Thanks a lot!
You can find a full explanation here, but shortly:
You can access query parameters directly from the view, the request object has a method. I suppose it is a GET request, so an example for your implementation would be:
request.GET.getlist("brand_id")
or
request.GET.get("brand_id")
Mainly, for what I wanted to do, it’s as easy as two steps.
First, add a column in list_display
to show the link to the add_view
:
Brand.py
@admin.display(description='Link', ordering='url')
def get_add_link(self):
url = f"{reverse('admin:myapp_car_add')}?brand={self.id}"
return format_html(f"<a href='{url}'><i class='fas fa-plus'></i></a>")
Note that I add the URL as the reverse of admin:<app>_<model>_<action>
and pass the brand ID as parameter.
CarAdmin.py
def get_changeform_initial_data(self, request):
brand_id = request.GET.get('brand')
return {'brand': brand_id}
By adding this method in the CarAdmin
class, I am able to set the brand as the default value.
Using django 3 i did it overriding get_form in CarAdmin.py like you did, and its working for me, maybe the trick is in Brand.py:
Brand.py
readonly_fields = ('get_add_link',)
def get_add_link(self, obj):
url = f"{reverse('admin:myapp_car_add')}?brand={self.id}"
return format_html(f"<a href='{url}'><i class='fas fa-plus'></i></a>")
CarAdmin.py
def get_form(self, request, obj=None, **kwargs):
form = super(CarAdmin, self).get_form(request, obj, **kwargs)
brand_id = request.GET.get('brand')
if brand_id and len(brand_id) > 0:
form.base_fields['brand'].initial = brand_id
I did not have to do anything with the Model
. The only change needed was in the ModelAdmin
:
def get_changeform_initial_data(self, request):
brand = None
brand_id = request.GET.get('brand')
if (brand_id):
brand = Brand.objects.get(id=brand_id)
return {'brand': brand}
Docs link here: https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_changeform_initial_data