James
James

Reputation: 93

Django: limit models.ForeignKey results

I have an order model:

class Order(models.Model):
    profile = models.ForeignKey(Profile, null=True, blank=True)

Which returns all possible profiles for an order, which is not necessary and slowing down the loading of the admin order page.

I want the profile returned to simply be the profile of the user who placed the order. I've tried changing it to:

class Order(models.Model):
    profile = models.ForeignKey(Profile, null=True, blank=True, limit_choices_to={'order': 99999})

which returns the correct profile for order number 99999, but how can I get this dynamically. The Order model is not aware of the 'self', but the order number is contained in the URL.

What is the best way to do this?

Upvotes: 0

Views: 419

Answers (3)

Keith Bailey
Keith Bailey

Reputation: 296

I assume from the context you're referring to the display on the Django Admin page. If you set raw_id_fields = {'my_foreign_key'}

you will get a number, text description of related model (from str) and a nice popup box to open an instance of the admin page for your related models.

You could alternatively use list_select_related = True to get the same behaivour you have now but with a couple of order of magnitudes lower number of queries.

Upvotes: 0

James
James

Reputation: 93

I took another look at this and it seems to be working, although it seems like a bit of hack! The problem was that the order number doesn't seem to exist in the request so I am parsing the URL requested. I put this in my order admin:

def formfield_for_foreignkey(self, db_field, request, **kwargs):
    if db_field.name == "profile":
        try:
            order = int(filter(str.isdigit, str(request.path_info)))
        except:
            order = request.GET.get('order')
        kwargs["queryset"] = Profile.objects.filter(order=order)
    return super(OrderAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

The line that filters the url string for an integer works for the change order page of the admin, but didn't work for the order page overview, so I added the try/except. Any suggestions/improvements welcome!

Upvotes: 0

Gustavo Carvalho
Gustavo Carvalho

Reputation: 178

If you are using the Django Admin, you can override the method formfield_for_foreignkey on your ModelAdmin class to modify the queryset for the profile field dinamically based on a GET parameter for instance (as you have access to request inside the method.

Look at this example from the docs (adapted for your case):

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "profile":
            # You can get the order number from the GET parameter:
            # order = request.GET.get('order')
            # or a fixed number:
            order = '12345'
            kwargs["queryset"] = Profile.objects.filter(order=order)
        return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

Reference in the docs: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey

Upvotes: 0

Related Questions