2013-11-27 46 views
3

因此,我嘗試創建將定義管理網站中管理相關模型的動態代理模型的模型時遇到了一些問題。我知道這句話很混亂,所以我只是分享我的代碼。爲相關模型創建代理模型的類別模型admin

models.py

class Cateogry(models.Model): 
    name = models.CharField(...) 

class Tag(models.Model): 
    name = models.CharField(...) 
    category = models.ForeignKey(Cateogry) 

我想實現的是在管理網站,而不必爲標籤模型一個的ModelAdmin,每個類別我會爲所有相關的標記一個的ModelAdmin。我已使用this answer達到此目的。說我有一個命名爲A類:

def create_modeladmin(modeladmin, model, name = None): 
    class Meta: 
     proxy = True 
     app_label = model._meta.app_label 

    attrs = {'__module__': '', 'Meta': Meta} 

    newmodel = type(name, (model,), attrs) 

    admin.site.register(newmodel, modeladmin) 
    return modeladmin 

class CatA(TagAdmin): 
    def queryset(self, request): 
     qs = super(CatA, self).queryset(request) 
     return qs.filter(cateogry = Cateogry.objects.filter(name='A')) 

create_modeladmin(CatA, name='CategoryAtags', model=Tag) 

但是,這還不夠好,因爲很明顯,我還需要手動子類TagAdmin模型,然後運行create_modeladmin。我需要做的是遍歷所有的Category對象,爲每個對象創建一個Tagadmin的動態子類(以該類別命名),然後創建一個動態代理模型,這就是我的頭開始旋轉的地方。

for cat in Category.objects.all(): 
    NewSubClass = #somehow create subclass of TagAdmin, the name should be '<cat.name>Admin' instead of NewSubClass 
    create_modeladmin(NewSubClass, name=cat.name, model=Tag) 

任何指導或幫助將不勝感激

回答

1

Dynamic ModelAdmins不能與管理員註冊模型的方式一起使用。 我建議在CategoryAdmin中創建子視圖。

from django.conf.urls import patterns, url 
from django.contrib import admin 
from django.contrib.admin.options import csrf_protect_m 
from django.contrib.admin.util import unquote 
from django.core.urlresolvers import reverse 

from demo_project.demo.models import Category, Tag 

class TagAdmin(admin.ModelAdmin): 
    # as long as the CategoryTagAdmin class has no custom change_list template 
    # there needs to be a default admin for Tags 
    pass 
admin.site.register(Tag, TagAdmin) 

class CategoryTagAdmin(admin.ModelAdmin): 
    """ A ModelAdmin invoked by a CategoryAdmin""" 

    read_only_fields = ('category',) 

    def __init__(self, model, admin_site, category_admin, category_id): 
     self.model = model 
     self.admin_site = admin_site 
     self.category_admin = category_admin 
     self.category_id = category_id 
     super(CategoryTagAdmin, self).__init__(model, admin_site) 

    def queryset(self, request): 
     return super(CategoryTagAdmin, self).queryset(request).filter(category=self.category_id) 


class CategoryAdmin(admin.ModelAdmin): 

    list_display = ('name', 'tag_changelist_link') 

    def tag_changelist_link(self, obj): 
     info = self.model._meta.app_label, self.model._meta.module_name 
     return '<a href="%s" >Tags</a>' % reverse('admin:%s_%s_taglist' % info, args=(obj.id,)) 
    tag_changelist_link.allow_tags = True 
    tag_changelist_link.short_description = 'Tags' 

    @csrf_protect_m 
    def tag_changelist(self, request, *args, **kwargs): 
     obj_id = unquote(args[0]) 
     info = self.model._meta.app_label, self.model._meta.module_name 

     category = self.get_object(request, obj_id) 

     tag_admin = CategoryTagAdmin(Tag, self.admin_site, self, category_id=obj_id) 

     extra_context = { 
      'parent': { 
       'has_change_permission': self.has_change_permission(request, obj_id), 
       'opts': self.model._meta, 
       'object': category, 
      }, 
     } 
     return tag_admin.changelist_view(request, extra_context) 


    def get_urls(self): 
     info = self.model._meta.app_label, self.model._meta.module_name 
     urls= patterns('', 
      url(r'^(.+)/tags/$', self.admin_site.admin_view(self.tag_changelist), name='%s_%s_taglist' % info) 
     ) 
     return urls + super(CategoryAdmin, self).get_urls() 


admin.site.register(Category, CategoryAdmin) 

在變更列表與由tag_changelist_link指向CategoryAdmin.tag_changelist做一個鏈接一個額外的列類別的項目。此方法創建一個帶有一些額外值的CategoryTagAdmin實例並返回其changelist_view。

這樣您就可以在每個類別上過濾標籤更改列表。要修復tag_changelist視圖的麪包屑,您需要將CategoryTagAdmin.change_list_template設置爲自己的模板{% extends 'admin/change_list.html' %}並覆蓋{% block breadcrumbs %}。那就是你將需要extra_context的parent變量來創建正確的url。

如果計劃實施tag_changeviewtag_addview方法,你需要確保在variouse管理模板提供的鏈接都指向正確的URL(例如調用帶有FORM_URL作爲放慢參數的change_view)。 在添加新標籤時,CategoryTagAdmin上的save_model方法可以設置默認類別。

def save_model(self, request, obj, form, change): 
    obj.category_id = self.category_id 
    super(CategoryTagAdmin, self).__init__(request, obj, form, change) 

如果你仍然想堅持apache重新啓動aproach ...是的,你可以重新啓動Django。這取決於你如何部署實例。 在apache上,您可以觸摸將重新加載實例os.utime(path/to/wsgi.py的wsgi文件。 使用uwsgi時,您可以使用uwsgi.reload()

可以檢查Rosetta源代碼,他們是如何重新啓動轉換保存(views.py)後的實例。

+0

這是一些該死的奇妙代碼就在那裏。儘管它還不完美,但它肯定給我指出了正確的方向,並且您還指出瞭如何重新啓動服務器的選項。非常感謝你,你得到了賞金,你非常值得! – yuvi

0

所以我找到了一個半解決方案。

def create_subclass(baseclass, name): 
    class Meta: 
     app_label = 'fun' 

    attrs = {'__module__': '', 'Meta': Meta, 'cat': name } 
    newsub = type(name, (baseclass,), attrs) 
    return newsub 

class TagAdmin(admin.ModelAdmin): 
    list_display = ('name', 'category') 
    def get_queryset(self, request): 
     return Tag.objects.filter(category = Category.objects.filter(name=self.cat)) 

for cat in Category.objects.all(): 
    newsub = create_subclass(TagAdmin, str(cat.name)) 
    create_modeladmin(newsub, model=Tag, name=str(cat.name)) 

它的工作。但是,每次添加新類別時,都需要在服務器顯示之前刷新服務器(因爲admin.py是在運行時進行評估的)。有沒有人知道一個體面的解決方案呢?