Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit choices of ForeignKey choices for Django raw_id_field

How do you limit what choices are shown for ForeignKey fields in Django's admin when they're displayed using the raw_id_fields option?

When rendered as a select box, it's simple to define a custom ModelForm to set that field's queryset value with the choices to want. However, this queryset appears to be completely ignored when rendered using raw_id_fields. It generates a link to that ForeignKey's model, allowing you to select any record from that model via a popup window. You can still filter these values by customizing the URL, but I can't find a way to do this via a ModelAdmin.

like image 528
Cerin Avatar asked May 12 '14 20:05

Cerin


2 Answers

I use similar to FSp approach in my Django 1.8 / Python 3.4 project:

from django.contrib import admin
from django.contrib.admin import widgets
from django.contrib.admin.sites import site
from django import forms

class BlogRawIdWidget(widgets.ForeignKeyRawIdWidget):
    def url_parameters(self):
        res = super().url_parameters()
        res['type__exact'] = 'PROJ'
        return res

class ProjectAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['blog'].queryset = Blog.objects.filter(type='PROJ')
        self.fields['blog'].widget = BlogRawIdWidget(rel=Project._meta.get_field('blog').remote_field, admin_site=site)

    class Meta:
        # Django 1.8 convenience:
        fields = '__all__'
        model = Project

class ProjectAdmin(admin.ModelAdmin):
    form = ProjectAdminForm
    raw_id_fields = ('blog',)

to select only blog.type == 'PROJ' as foreign key Project.blog in django.admin. Because end-users may and will to select anything, unfortunately.

like image 182
Dmitriy Sintsov Avatar answered Oct 21 '22 11:10

Dmitriy Sintsov


The method below works for me but it is a queryset that affects every admin that needs to use the Customer model. But if you have another Admin, e.g. Invoice that requires a different queryset, you might want to experiment a bit with model proxy.

Model

class Customer(models.Model):
    name = models.CharField(max_length=100)
    is_active = models.BooleanField()

class Order(models.Model):
    cust = models.ForeignKey(Customer)

Admin

class CustomerAdmin(admin.ModelAdmin):         
    def queryset(self, request):
        qs = super(CustomerAdmin, self).queryset(request)           
        return qs.filter(is_active=1)

class OrderAdmin():     
    raw_id_fields = ('cust', )    
like image 34
user2473168 Avatar answered Oct 21 '22 12:10

user2473168