我正在为我的公司开发一个媒体网站,其中包含大量数据(研究出版物、数百名员工等)和安全限制,这让我想到使用django-guardian来处理对象权限。但现在我意识到,这在管理层内部可能很慢。
我们已经实现了一个redis缓存,它似乎工作得很好,但加载大列表视图(数百个元素)仍然需要很长时间。
到目前为止,我们正在使用以下设置:
django 1.5.5
django-cms 2.4.3
django-redis-cache 0.10.2
django-guardian 1.1.1
hiredis 0.1.2
redis 2.9.1
python 2.7.5
postgresql
centos
例如,这是Person模块,其列表视图需要很长时间才能加载(不是作为超级用户,在这种情况下它非常快:这就是为什么我认为问题在于django-guardian多重关系):
class Person(models.Model):
TYPE_CHOICES = (
('S', _('Student')),
('E', _('Researcher')),
)
class Meta:
permissions = (
('view_person', _('View person')),
)
index_together = (
('last_name', 'first_name'),
)
# Relations with other entities
topics = models.ManyToManyField('topics.Topic', blank=True, related_name='people')
competences = models.ManyToManyField('staff.Competence', blank=True, related_name='people', db_index=True)
# Person properties
cmsuser = models.OneToOneField(User, blank=True, related_name='person', null=True, db_index=True)
sebra_username = models.CharField(max_length=20, blank=True, db_index=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True, db_index=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True, db_index=True)
email = models.EmailField(_('email address'), blank=True, db_index=True)
username = models.CharField(_('username'), max_length=30, unique=True, db_index=True)
avatar = models.ImageField(upload_to='img/avatar/', blank=True)
web = models.URLField(_("web site"), blank=True)
cristin_profile = models.URLField(_('link to cristin profile'), blank=True)
twitter = models.CharField(_("twitter username"), max_length=20, blank=True)
telephone = models.CharField(
blank=True,
max_length=validators.MAX_LENGTH_PHONE,
validators=[validators.validate_phone_format]
)
telephone_country_code = models.ForeignKey(Country, null=True, blank=True, related_name='phone_person')
mobile = models.CharField(
blank=True,
max_length=validators.MAX_LENGTH_PHONE,
validators=[validators.validate_phone_format]
)
mobile_country_code = models.ForeignKey(Country, null=True, blank=True, related_name='mobile_person')
address = models.TextField(max_length=255, blank=True)
cv = models.FileField(_('Curriculum Vitae'), upload_to='attachments/cv/', blank=True)
vcard = models.FileField(_('Vcard'), upload_to='attachments/vcard/', blank=True)
person_type = models.CharField(choices=TYPE_CHOICES, max_length=1, blank=True)
extract = RichTextField(_('person extract'), blank=True, default='')
slug = AutoSlugField(populate_from=('first_name', 'last_name'))
def __unicode__(self):
if len(self.first_name) + len(self.last_name):
return '%s %s' % (self.first_name, self.last_name)
return self.username
def clean(self):
super(Person, self).clean()
if self.sebra_username.strip():
# here goes validation and checks on the related objects
def get_absolute_url(self):
if PersonDepartmentMembership.objects.filter(active__exact=True, person__exact=self):
return reverse('staff:profile_slug', kwargs={'slug': self.slug})
return ''
我知道瓶颈可能也在我的Admin类中。这是我们正在使用的:
class PersonAdmin(ModelAdmin):
fields = (
'sebra_username', 'first_name', 'last_name', 'avatar', 'email', 'person_type', 'extract',
'topics', 'competences', 'web', 'cristin_profile', 'twitter', 'telephone_country_code',
'telephone', 'address', 'mobile_country_code', 'mobile', 'cv', 'vcard'
)
search_fields = ('sebra_username', 'first_name', 'last_name', 'email', 'departments__name')
list_filter = ('departments__name', 'research_groups__group_name', 'projects__project_name')
inlines = (SomeInline,)
class Media:
js = (
settings.STATIC_URL + 'js/jquery-1.9.0.min.js',
settings.STATIC_URL + 'js/jquery-ui-1.9.2.custom.min.js',
'modeltranslation/js/tabbed_translation_fields.js',
)
css = {
'screen': ('modeltranslation/css/tabbed_translation_fields.css',),
}
def formfield_for_manytomany(self, db_field, request=None, **kwargs):
if db_field.name == 'topics':
kwargs['queryset'] = get_objects_for_user(user=request.user, perms=('topics.view_topic',))
elif db_field.name == 'competences':
kwargs['queryset'] = get_objects_for_user(user=request.user, perms=('staff.view_competence',))
return super(PersonAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
def queryset(self, request):
if request.user.is_superuser:
return super(PersonAdmin, self).queryset(request)
return get_objects_for_user(user=request.user, perms=('staff.change_person',)).order_by('last_name')
def has_add_permission(self, request):
return request.user.has_perm('staff.add_person')
def has_delete_permission(self, request, obj=None):
return request.user.has_perm('staff.delete_person', obj)
def has_change_permission(self, request, obj=None):
return request.user.has_perm('staff.change_person', obj)
你能给我任何建议或建议我任何可能的解决方案,我们可以在管理界面中集成吗?:-)
提前感谢!
编辑:
使用django-debug工具栏,我可以看到对django-guardian的查询很少,而且速度很快(均低于6ms)。另一方面,对于263的列表视图,我有7500多个查询,这将视图的生成速度减慢到46秒。几乎所有这些都在我定义的模型中,用来加载(我认为)无用的数据:我认为只需要名称和对象id。
如何限制queryset()方法中加载的数据量?谢谢
如果你正在执行7500个查询,你的问题可能是你没有加载你需要的相关对象-下面是我要看的:
- 您的模型上有访问相关对象的方法吗
- 您的
list_display
设置中是否有访问相关对象的项目
要么取消对这些东西的调用,要么查看select_related
。
此外,尝试更改管理视图的分页-如果减少显示的记录数量-查询会减少多少?这会让你知道你有多少这样的问题。