31👍
Django < 2.0 Answer:
Use Django’s Request object (which you have access to) to retrieve the request.path_info
, then retrieve the PK from the args in the resolve
match. Example:
from django.contrib import admin
from django.core.urlresolvers import resolve
from app.models import YourParentModel, YourInlineModel
class YourInlineModelInline(admin.StackedInline):
model = YourInlineModel
def get_parent_object_from_request(self, request):
"""
Returns the parent object from the request or None.
Note that this only works for Inlines, because the `parent_model`
is not available in the regular admin.ModelAdmin as an attribute.
"""
resolved = resolve(request.path_info)
if resolved.args:
return self.parent_model.objects.get(pk=resolved.args[0])
return None
def has_add_permission(self, request):
parent = self.get_parent_object_from_request(request)
# Validate that the parent status is active (1)
if parent:
return parent.status == 1
# No parent - return original has_add_permission() check
return super(YourInlineModelInline, self).has_add_permission(request)
@admin.register(YourParentModel)
class YourParentModelAdmin(admin.ModelAdmin):
inlines = [YourInlineModelInline]
Django >= 2.0 Answer:
Credit to Mark Chackerian for the below update:
Use Django’s Request object (which you have access to) to retrieve the request.path_info
, then retrieve the PK from the args in the resolve
match. Example:
from django.contrib import admin
from django.urls import resolve
from app.models import YourParentModel, YourInlineModel
class YourInlineModelInline(admin.StackedInline):
model = YourInlineModel
def get_parent_object_from_request(self, request):
"""
Returns the parent object from the request or None.
Note that this only works for Inlines, because the `parent_model`
is not available in the regular admin.ModelAdmin as an attribute.
"""
resolved = resolve(request.path_info)
if resolved.args:
return self.parent_model.objects.get(pk=resolved.args[0])
return None
def has_add_permission(self, request):
parent = self.get_parent_object_from_request(request)
# Validate that the parent status is active (1)
if parent:
return parent.status == 1
# No parent - return original has_add_permission() check
return super(YourInlineModelInline, self).has_add_permission(request)
@admin.register(YourParentModel)
class YourParentModelAdmin(admin.ModelAdmin):
inlines = [YourInlineModelInline]
24👍
I think this is a cleaner way to get the parent instance in the inline model.
class ChildInline(admin.TabularInline):
model = Child
form = ChildForm
fields = (...)
extra = 0
def get_formset(self, request, obj=None, **kwargs):
self.parent_obj = obj
return super(ChildInline, self).get_formset(request, obj, **kwargs)
def has_add_permission(self, request):
# Return True only if the parent has status == 1
return self.parent_obj.status == 1
class ParentAdmin(admin.ModelAdmin):
inlines = [ChildInline, ]
- [Django]-[Django][AWS S3] botocore.exceptions.clienterror an error occurred (accessdenied) when calling the PutObject operation
- [Django]-How do I do an OR filter in a Django query?
- [Django]-Django F expressions joined field
5👍
I tried the solution of Michael B but didn’t work for me, I had to use this instead (a small modification that uses kwargs):
def get_parent_object_from_request(self, request):
"""
Returns the parent object from the request or None.
Note that this only works for Inlines, because the `parent_model`
is not available in the regular admin.ModelAdmin as an attribute.
"""
resolved = resolve(request.path_info)
if resolved.kwargs:
return self.parent_model.objects.get(pk=resolved.kwargs["object_id"])
return None
- [Django]-Why does my Django admin site not have styles / CSS loading?
- [Django]-Iterate over model instance field names and values in template
- [Django]-How do I display the Django '__all__' form errors in the template?
1👍
BaseInlineFormSet has the attribute self.instance
which is the reference to the parent object.
In the constructor, the queryset is intialized and filtered using this instance. If you need adjustments, you can change the queryset argument to the constructor or use inlineformset_factory
to set the formset up according to your needs.
class BaseInlineFormSet(BaseModelFormSet):
"""A formset for child objects related to a parent."""
def __init__(self, data=None, files=None, instance=None,
save_as_new=False, prefix=None, queryset=None, **kwargs):
if instance is None:
self.instance = self.fk.remote_field.model()
else:
self.instance = instance
self.save_as_new = save_as_new
if queryset is None:
queryset = self.model._default_manager
if self.instance.pk is not None:
qs = queryset.filter(**{self.fk.name: self.instance})
else:
qs = queryset.none()
self.unique_fields = {self.fk.name}
super().__init__(data, files, prefix=prefix, queryset=qs, **kwargs)
see https://docs.djangoproject.com/en/3.2/_modules/django/forms/models/
If you extends from this, make sure to run super().__init__()
before accessing self.instance
.
- [Django]-Is there a list of Pytz Timezones?
- [Django]-Django: Detect database backend
- [Django]-ValueError: Missing staticfiles manifest entry for 'favicon.ico'
1👍
Place the following on the parent admin model so that the parent model instance is available to any inline under the parent model:
def get_form(self, request, obj=None, **kwargs):
request._obj = obj
return super().get_form(request, obj, **kwargs)
Then, in the inline (using a customers
field as an example):
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "customers":
if request._obj is not None:
kwargs["queryset"] = request._obj.customers
else:
kwargs["queryset"] = Customer.objects.none()
return super().formfield_for_manytomany(db_field, request, **kwargs)
- [Django]-Profiling Django
- [Django]-Django error – matching query does not exist
- [Django]-Django rest framework, use different serializers in the same ModelViewSet
0👍
You only need to add obj parameter and check the parent model status
class ChildInline(admin.TabularInline):
model = Child
form = ChildForm
fields = (
...
)
extra = 0
#You only need to add obj parameter
#obj is parent object now you can easily check parent object status
def has_add_permission(self, request, obj=None):
if obj.status == 1:
return True
else:
return False
class ParentAdmin(admin.ModelAdmin):
inlines = [ChildInline,]
- [Django]-How to upload multiple files in django rest framework
- [Django]-How to view corresponding SQL query of the Django ORM's queryset?
- [Django]-Rendering a value as text instead of field inside a Django Form
0👍
You can also retrieve it simply from the request path using re module if you do not expect numbers in your path.
for example:
import re
def get_queryset(self, request):
instance_id = re.sub(r"\D+", "", request.path)
or
def get_parent_object_from_request(self, request):
instance_id = re.sub(r"\D+", "", request.path)
- [Django]-Django: Increment blog entry view count by one. Is this efficient?
- [Django]-How can I disable Django's admin in a deployed project, but keep it for local development?
- [Django]-Import csv data into database in Django Admin