很多外键 - Django Admin

Posted

技术标签:

【中文标题】很多外键 - Django Admin【英文标题】:A lots of foreign keys - Django Admin 【发布时间】:2012-09-16 10:07:49 【问题描述】:

有一个SQL问题,添加这个模型一切正常,问题出在ADMIN。

当我向每个表添加少量数据时,通过单击ADMIN 中的TYPEPAGE,页面加载速度非常慢,安装debug_toolbar 和SQL 花了17 秒为TYPE。当我尝试PAGE 它给了我超时,我的问题是我的模型有什么问题?是不是结构不好?

我的目标是这个例子:

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

基本上所有 6 个 url 都是动态的,我会在每个表中指定它们,并且会在 PAGE 中作为下拉列表出现在其他表中。执行此操作或优化模型的最佳方法是什么?

这是TYPE页面加载的截图:

截图:http://cl.ly/image/2931040E0t35

请帮忙谢谢

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)

当我从admin.pylist_display 中删除外键时,我也发现它的工作速度非常快:

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)

外键不能在 list_display 中?如何优化它们?

更新:

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)

更新 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)

更新 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)

【问题讨论】:

每张表有多少条记录? auto_client = 3 行,auto_category = 2 行,auto_subcategory = 2 行,auto_project = 5 行,auto_type = 2 行,auto_page = 0 - 因为单击 auto_page 它会因为 SQL 查询而超时。基本上像 14 条记录一样 :),这也是 phpmyadmin 中的 mysql 查询:cl.ly/image/2S320h3d0P0J 17 秒,还有来自 debug_toolbar 的截图:cl.ly/image/081h1l3X1D28 外键不能在 list_display 中?如何优化它们? 为什么不使用主键来建立关系?您正在进行大量连接,并且对非主键的字段执行关系。想想数据库模式,这不是标准方法。您能解释一下为什么采用这种方法吗? 你能在上面的解决方案上举一个例子,我应该如何正确地制作它,这对我很有帮助,稍后我想在管理员中使用 django-smart-select 进行下拉菜单,它可以动态过滤如果我选择 clent 它将刷新其他人并且它可以工作但是发生了长 SQL 查询我认为它是 django-smart-select 插件所以我删除它并将它重写为外键但是如果你能告诉我正确的布局会很棒:) 【参考方案1】:

您可以使用 django admin 的 raw_id_fields 选项来代替它。

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)

【讨论】:

哇,不知道“raw_id_fields”是如何工作的,如果可能的话,你能解释一下吗?它加载速度很快,我怎样才能实现例如包含在模型中的 list_display“标题”中,但不能将它放在用于外键和多对多的“raw_id_fields”中......谢谢将添加数据并进行测试 您使用外键,并且在管理页面中,当您想单击页面 admin 时,django 会尝试获取并加入它的相关所有对象。你可以看看 django 文档:docs.djangoproject.com/en/dev/ref/contrib/admin/…【参考方案2】:

嗯,我不确定这是否 100% 相关(因为我在 list_display and list_editable 中使用了 FK)。我使用这里描述的技巧来加快速度: http://blog.ionelmc.ro/2012/01/19/tweaks-for-making-django-admin-faster/

似乎对每一行的选择都进行了评估(尤其是在对 FK 使用 list_editable 时),因此使用 formfield_for_dbfield 您可以按照链接中的建议缓存选择。这节省了去数据库渲染foreign_keys的每个下拉/选择框。

如果您打开 mysql 常规日志(如果您使用的是 MySQL),您可以在视图上看到正在执行的查询。

【讨论】:

以上是关于很多外键 - Django Admin的主要内容,如果未能解决你的问题,请参考以下文章

Django Admin 自定义外键选择框

在 django admin 中使用外键访问另一个模型字段

django admin 添加用户出现外键约束错误

在 django admin 中链接到外键对象

在搜索字段中正确使用外键引用,Django admin

Django admin禁用外键下拉但保留添加按钮旁边