سؤال

I have an admin site instance on my django site and followng models.

class Board(models.Model):
    slug = models.SlugField(verbose_name = _('Slug'))
    name = models.CharField(max_length=200, verbose_name = _('Name'))

class Category(models.Model):
    board = models.ForeignKey(Board)
    slug = models.SlugField(verbose_name = _('Slug'))
    name = models.CharField(max_length=200, verbose_name = _('Name'))

class Message(models.Model):
    board = models.ForeignKey(Board)
    category = models.ForeignKey(Category)
    name = models.CharField(max_length=200, verbose_name = _('Name'))

How can I set some board as a context for admin site? So in messages list will be messages only from this board and when editing some message it is possible to select only categories from this board?

I tried to add some param into url and override modeladmin queryset like this:

url(r'^manage-board/(?P<board_slug>[-\w]+)', include(board_admin.urls)),

class MessageAdmin(PinAdmin):
def queryset(self, request):
    board_slug = resolve(request.path).args.get('board_slug')
    if board_slug:
      return Pin.objects.filter(board__slug = board_slug)
    else:
      return None

But unfortunately this way doesn't work because it captures additional param and shows error.

هل كانت مفيدة؟

المحلول

I fixed error with param capture in url by overriding admin_view method in custom AdminSite. But unfortunately there is no way to fix errors from reverse url lookup because admin site knows nothing about param. After some investigation I found a way to workaround that problem with additional middleware class. Whole solution:

urls.py

url(r'^manage-board/', include(board_admin.urls)),

middleware.py

import re
r = re.compile(r'^/manage-board/(?P<board_slug>[-\w]+)/')

class AdminMiddleware(object):
    def process_request(self, request):
        match=r.search(request.path)
        if match:
            match = match.groupdict()
            request.board_slug = match.get('board_slug')
            request.path = request.path.replace('manage-board/'+ request.board_slug,'manage-board')
            request.path_info = request.path_info.replace('manage-board/'+   request.board_slug,'manage-board')

    def process_response(self, request, response):
        if hasattr(request, 'board_slug'):
            response.content = response.content.decode('utf-8').replace("/manage-board/", u"/manage-board/%s/" % request.board_slug).encode('utf-8')
        return response

admin.py

class BoardModelAdmin(admin.ModelAdmin):
    exclude = ('board',)
    def queryset(self, request):
        qs = super(BoardModelAdmin, self).queryset(request)
        if hasattr(request, 'board_slug'):
            return qs.filter(board__slug = request.board_slug)
        else:
            return qs

    def save_model(self, request, obj, form, change):
        if hasattr(request, 'board_slug'):
            obj.board = Baord.objects.get(slug = request.board_slug)
        super(BoardModelAdmin, self).save_model(request, obj, form, change)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "category" and hasattr(request, 'board_slug'):
            kwargs["queryset"] = Category.objects.filter(board__slug=request.board_slug)
        return super(BoardModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

class BoardRelatedFieldListFilter(RelatedFieldListFilter):
    def __init__(self, field, request, params, model, model_admin, field_path):
        super(BoardRelatedFieldListFilter, self).__init__(field, request, params, model, model_admin, field_path)
        if hasattr(request, 'board_slug'):
            self.lookup_choices = [(instance.pk, smart_unicode(instance)) for instance in field.rel.to.objects.filter(board__slug=request.board_slug)]

class MessageAdmin(BoardModelAdmin):
    list_filter = [('category', BoardRelatedFieldListFilter)]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top