所以我在尝试创建一个模型时遇到了一些麻烦,该模型将定义管理管理站点中相关模型的动态代理模型。我知道这句话令人困惑,所以我只会分享我的代码。
models.py
class Cateogry(models.Model):
name = models.CharField(...)
class Tag(models.Model):
name = models.CharField(...)
category = models.ForeignKey(Cateogry)
我想要实现的是,在管理站点中,不是为Tag模型设置一个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)
非常感谢任何指导或帮助
答案 0 :(得分:1)
动态ModelAdmins与admin注册模型的方式不兼容。 我建议在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_changeview
和tag_addview
方法,则需要确保在variouse管理模板中呈现的链接指向正确的网址(例如,使用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 restart aproach ...是的,你可以重启Django。这取决于您部署实例的方式。
在apache上,您可以触摸将重新加载实例os.utime(path/to/wsgi.py
的wsgi文件。
使用uwsgi时,您可以使用uwsgi.reload()
。
您可以在保存翻译(views.py)后检查Rosetta源代码如何重新启动实例。
答案 1 :(得分: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)。有没有人知道一个合适的解决方案?