大量のデータ (研究出版物、数百人の従業員など) とセキュリティ上の制約があるため、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 ''
ボトルネックが私の管理者クラスにもある可能性があることを理解しています。これは私たちが使用しているものです:
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-toolbar を使用すると、django-guardian へのクエリが非常に少なく、非常に高速 (すべて 6 ミリ秒未満) であることがわかります。一方、263 のリストビューに対して 7500 を超えるクエリがあり、ビューの生成に最大 46 秒かかります。それらのほとんどすべては、役に立たないデータをロードするために、定義したモデル内にあります (私はそう思います): 名前とオブジェクト ID だけが必要だと思います。
queryset() メソッド内でロードされるデータの量を制限するにはどうすればよいですか? ありがとう。