Reputation: 8836
Here in my django ModelAdmin I want to filter foreignkey choices based on current user's group and I want to achieve it both in add and change form. I have achieved it in add view by using following code.
add_view
def add_view(self, request, form_url = '', extra_context = None):
service_sector = common.getServiceSector(request.user)
ModelForm = self.get_form(request)
if request.POST:
form = ModelForm(request.POST, request.FILES)
else:
form = ModelForm()
if service_sector:
qs = form['member'].field.queryset
qs = qs.filter(service_sector = service_sector)
form['member'].field.queryset = qs
adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)),
self.prepopulated_fields, self.get_readonly_fields(request),
model_admin=self)
context = {
'adminform': adminForm,
'is_popup': "_popup" in request.REQUEST,
'show_delete': False,
'root_path': self.admin_site.root_path,
}
context.update(extra_context or {})
return self.render_change_form(request, context, form_url=form_url, add=True)
Here it is working fine. In this model I have a unique field Email and that is causing the problem in change_view. I have given my change_view code below.
change_view
def change_view(self, request, object_id, form_url = '', extra_context = None):
qs = self.model._default_manager.get_query_set()
service_sector = common.getServiceSector(request.user)
bene_object = Beneficiary.objects.get(pk=object_id)
ModelForm = self.get_form(request, bene_object)
if request.POST:
form = ModelForm(request.POST, request.FILES)
else:
form = ModelForm(instance=bene_object)
if service_sector:
qs = form['member'].field.queryset
qs = qs.filter(service_sector = service_sector)
form['member'].field.queryset = qs
adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)),
self.prepopulated_fields, self.get_readonly_fields(request),
model_admin=self)
context = {
'adminform': adminForm,
'is_popup': "_popup" in request.REQUEST,
'show_delete': False,
'root_path': self.admin_site.root_path,
}
context.update(extra_context or {})
return self.render_change_form(request, context, form_url = form_url, change = True)
Even though I have given change = True
in my change_view return, it is trying to save the object as new one. So I'm getting an error Email already exists
as the email field is unique value field. Or is it possible to use the normal change_view return as follows:
return super(ModelAdmin, self).change_view(request, form_url, extra_context)
If so, how can I filter foreignkey choices. Or how to use render_change_form
to achieve this? Thanks in advance.
Upvotes: 1
Views: 6702
Reputation: 8836
I have resolved this issue and posting the answer here which may help others. The question here helped me to fix this issue. With the following code I have done foreignkey filter based on user's group, for both add and change form in django admin with inline formsets in it. I'm giving the code below:
def render_change_form(self, request, context, *args, **kwargs):
model = self.model
opts = model._meta
formsets = []
#Change view
if 'change' in kwargs.keys():
object_id = kwargs['obj'].id #To get object id
object = Modelobjects.get(pk=object_id)
ModelForm = self.get_form(request, object)
qs = self.model._default_manager.get_query_set()
if request.POST:
form = ModelForm(request.POST, request.FILES)
else:
form = ModelForm(instance = object)
service_sector = common.getServiceSector(request.user)
if service_sector:
#To filter foreignkey
qs = form['member'].field.queryset
qs = qs.filter(service_sector = service_sector)
form['member'].field.queryset = qs
adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)),
self.prepopulated_fields, self.get_readonly_fields(request),
model_admin=self)
media = self.media + adminForm.media
#To get inline formsets used
prefixes = {}
for FormSet, inline in zip(self.get_formsets(request),
self.inline_instances):
prefix = FormSet.get_default_prefix()
prefixes[prefix] = prefixes.get(prefix, 0) + 1
if prefixes[prefix] != 1:
prefix = "%s-%s" % (prefix, prefixes[prefix])
formset = FormSet(instance=object, prefix=prefix,
queryset=inline.queryset(request))
formsets.append(formset)
inline_admin_formsets = []
for inline, formset in zip(self.inline_instances, formsets):
fieldsets = list(inline.get_fieldsets(request))
readonly = list(inline.get_readonly_fields(request))
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
fieldsets, readonly, model_admin=self)
inline_admin_formsets.append(inline_admin_formset)
media = media + inline_admin_formset.media
else:
#Add view
ModelForm = self.get_form(request)
qs = self.model._default_manager.get_query_set()
if request.POST:
form = ModelForm(request.POST, request.FILES)
else:
form = ModelForm()
service_sector = common.getServiceSector(request.user)
if service_sector:
qs = form['member'].field.queryset
qs = qs.filter(service_sector = service_sector)
form['member'].field.queryset = qs
adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)),
self.prepopulated_fields, self.get_readonly_fields(request),
model_admin=self)
media = self.media + adminForm.media
prefixes = {}
for FormSet, inline in zip(self.get_formsets(request),
self.inline_instances):
prefix = FormSet.get_default_prefix()
prefixes[prefix] = prefixes.get(prefix, 0) + 1
if prefixes[prefix] != 1:
prefix = "%s-%s" % (prefix, prefixes[prefix])
formset = FormSet(instance=self.model(), prefix=prefix,
queryset=inline.queryset(request))
formsets.append(formset)
inline_admin_formsets = []
for inline, formset in zip(self.inline_instances, formsets):
fieldsets = list(inline.get_fieldsets(request))
readonly = list(inline.get_readonly_fields(request))
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
fieldsets, readonly, model_admin=self)
inline_admin_formsets.append(inline_admin_formset)
media = media + inline_admin_formset.media
context = {
'adminform': adminForm,
'title': _('Add %s') % force_unicode(opts.verbose_name),
'is_popup': "_popup" in request.REQUEST,
'show_delete': False,
'media': mark_safe(media),
'inline_admin_formsets': inline_admin_formsets,
'root_path': self.admin_site.root_path,
}
return super(ModelAdmin, self).render_change_form(request, context, args, kwargs)
Here the object id is obtained from kwargs['obj'].id
and foreignkey is filtered by
qs = form['member'].field.queryset
qs = qs.filter(service_sector = service_sector)
form['member'].field.queryset = qs
Here common.getServiceSector
is a custom method I'm using for my foreignkey filter conditions. You can define your own method for your requirements. Hope this will be helpful to others. Thanks.
Upvotes: 5