Search code examples
sqldjangoquery-optimizationadminmodels

A lots of foreign keys - Django Admin


Have a SQL problem, adding this model all works correctly, the problem is in ADMIN.

When I add the data just few to each table, by clicking on TYPE & PAGE in ADMIN the page is loading so slow, installed debug_toolbar and SQL took 17 seconds for the TYPE. When I tried the PAGE it gave me timeout, my question is what is wrong with my model? Is it constructed bad?

My goal is this lets say example:

http://www.example.com/audi/4doors/s4/sport/red/audi-url

Basically all 6 urls are dynamic that I would specify in the each table and would be in the PAGE as dropdowns also in others. What is the optimal way to do that or optimize the model?

Here is a screenshot of TYPE page loading:

screenshot: http://cl.ly/image/2931040E0t35

Please help thanks

from django.db import models

class Client(models.Model):
    title = models.CharField(max_length=100, unique=True)
    def __unicode__(self):
        return self.title

class Category(models.Model):
    client = models.ForeignKey(Client, to_field='title')
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Subcategory(models.Model):
    client = models.ForeignKey(Client, to_field='title')
    category = models.ForeignKey(Category, to_field='title')
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Project(models.Model):
    client = models.ForeignKey(Client, to_field='title')
    category = models.ForeignKey(Category, to_field='title')
    subcategory = models.ForeignKey(Subcategory, to_field='title')
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Type(models.Model):
    client = models.ForeignKey(Client, to_field='title')
    category = models.ForeignKey(Category, to_field='title')
    subcategory = models.ForeignKey(Subcategory, to_field='title')
    project = models.ForeignKey(Project, to_field='title')
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Page(models.Model):
    client = models.ForeignKey(Client, to_field='title')
    category = models.ForeignKey(Category, to_field='title')
    subcategory = models.ForeignKey(Subcategory, to_field='title')
    project = models.ForeignKey(Project, to_field='title')
    type = models.ForeignKey(Type, to_field='title')
    pageurl = models.CharField(max_length=200)

Also just found out when I remove Foreign Keys from admin.py from list_display, it works blazing fast:

class ClientAdmin(admin.ModelAdmin):
    list_display = ('title',)
    admin.site.register(Client, ClientAdmin)

class CategoryAdmin(admin.ModelAdmin):
    list_display = ('client', 'title',)
    admin.site.register(Category, CategoryAdmin)

class SubcategoryAdmin(admin.ModelAdmin):
    list_display = ('client', 'category', 'title', )
    admin.site.register(Subcategory, SubcategoryAdmin)

class ProjectAdmin(admin.ModelAdmin):
    list_display = ('client', 'category', 'subcategory', 'title', )
    admin.site.register(Project, ProjectAdmin)

class TypeAdmin(admin.ModelAdmin):
    list_display = ('client', 'title', )
    admin.site.register(Type, TypeAdmin)

class PageAdmin(admin.ModelAdmin):
    list_display = ('client', )
    admin.site.register(Page, PageAdmin)

FOREIGN KEYS cannot be in list_display? How to optimize them?

Update:

class Client(models.Model):
    title = models.CharField(max_length=100, unique=True, db_index=True)
    def __unicode__(self):
        return self.title

class Category(models.Model):
    client = models.ForeignKey(Client)
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Subcategory(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Project(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    subcategory = models.ForeignKey(Subcategory)
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Type(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    subcategory = models.ForeignKey(Subcategory)
    project = models.ForeignKey(Project)
    title = models.CharField(max_length=200, unique=True)
    def __unicode__(self):
        return self.title

class Page(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    subcategory = models.ForeignKey(Subcategory)
    project = models.ForeignKey(Project)
    type = models.ForeignKey(Type)
    pageurl = models.CharField(max_length=200)

UPDATE 2

from django.db import models


class Client(models.Model):
    title = models.CharField(max_length=100, primary_key=True)
    def __unicode__(self):
        return self.title

class Category(models.Model):
    client = models.ForeignKey(Client)
    title = models.CharField(max_length=200, primary_key=True)
    def __unicode__(self):
        return self.title

class Subcategory(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    title = models.CharField(max_length=200, primary_key=True)
    def __unicode__(self):
        return self.title

class Project(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    subcategory = models.ForeignKey(Subcategory)
    title = models.CharField(max_length=200, primary_key=True)
    def __unicode__(self):
        return self.title

class Type(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    subcategory = models.ForeignKey(Subcategory)
    project = models.ForeignKey(Project)
    title = models.CharField(max_length=200, primary_key=True)
    def __unicode__(self):
        return self.title

class Page(models.Model):
    client = models.ForeignKey(Client)
    category = models.ForeignKey(Category)
    subcategory = models.ForeignKey(Subcategory)
    project = models.ForeignKey(Project)
    type = models.ForeignKey(Type)
    pageurl = models.CharField(max_length=200)

UPDATE 3 - ADMIN.PY

class ClientAdmin(admin.ModelAdmin):

    list_display = ('title',)

admin.site.register(Client, ClientAdmin)

class CategoryAdmin(admin.ModelAdmin):

    list_display = ('client', 'title',)

admin.site.register(Category, CategoryAdmin)

class SubcategoryAdmin(admin.ModelAdmin):

    list_display = ('client', 'category', 'title', )

admin.site.register(Subcategory, SubcategoryAdmin)

class ProjectAdmin(admin.ModelAdmin):

        list_display = ('client', 'category', 'subcategory', 'title', )

admin.site.register(Project, ProjectAdmin)

class TypeAdmin(admin.ModelAdmin):

    list_display = ('client', 'category', 'subcategory', 'project', 'title', )

admin.site.register(Type, TypeAdmin)

class PageAdmin(admin.ModelAdmin):

   list_display = ('client', 'category', 'subcategory', 'project', 'type', 'pageurl', )

admin.site.register(Page, PageAdmin)

Solution

  • Instead of that you can use raw_id_fields option of django admin.

    admin.site.register(Client)
    
    class CategoryAdmin(admin.ModelAdmin):
    
        raw_id_fields = ('client',)
    
    admin.site.register(Category, CategoryAdmin)
    
    class SubcategoryAdmin(admin.ModelAdmin):
    
        raw_id_fields = ('client', 'category')
    
    admin.site.register(Subcategory, SubcategoryAdmin)
    
    class ProjectAdmin(admin.ModelAdmin):
    
        raw_id_fields = ('client', 'category', 'subcategory')
    
    admin.site.register(Project, ProjectAdmin)
    
    class TypeAdmin(admin.ModelAdmin):
    
        raw_id_fields = ('client', 'category', 'subcategory', 'project')
    
    admin.site.register(Type, TypeAdmin)
    
    class PageAdmin(admin.ModelAdmin):
    
        raw_id_fields = ('client', 'category', 'subcategory', 'project', 'type')
    
    admin.site.register(Page, PageAdmin)
    

    this is the old one this is new sql query