2012-03-26 13 views
23

Hãy nói rằng tôi có một ứng dụng blog đơn giản trong Django 1.4:Thêm một ManyToManyWidget đến mặt trái của một ManyToManyField trong Django quản

class Post(models.Model): 
    title = … 
    published_on = … 
    tags = models.ManyToManyField('Tag') 

class Tag(models.Model): 
    name = … 

tức là một bài có nhiều thẻ. Trên quản trị Django, tôi nhận được một chút đẹp <select multi> nếu tôi bao gồm tags trong fields cho số PostAdmin. Có cách nào dễ dàng để bao gồm danh sách các bài đăng (đơn giản là <select multi>) trong số TagAdmin không? Tôi đã thử đặt fields = ['name', 'posts'] vào số TagAdmin và gặp lỗi ImproperlyConfigured. (cùng một kết quả cho post_set).

Tôi ổn với Django, vì vậy có thể tạo một đối tượng AdminForm và Admin thích hợp, nhưng tôi hy vọng có một Way Right ™ để làm điều đó.

+0

Bạn đang tìm kiếm chỉnh sửa nội tuyến? https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-models – Jingo

+0

Bạn có thể thiết lập mô hình trung gian bằng cách sử dụng thuộc tính 'through' và thiết lập một vài dòng trong Quản trị viên. Nhưng đó là xa giải pháp đẹp. Hãy xem vé này: https://code.djangoproject.com/ticket/897 – ilvar

+1

Tôi đang tìm kiếm một điều tương tự - dường như đủ đơn giản. Bạn đã bao giờ tìm thấy một giải pháp? –

Trả lời

10

Một chút muộn để đảng, nhưng đây là giải pháp mà làm việc cho tôi (không có phép thuật):

# admin.py 

from django.contrib import admin 
from models import Post 

class TagPostInline(admin.TabularInline): 
    model = Post.tags.through 
    extra = 1 

class PostAdmin(admin.ModelAdmin): 
    inlines = [TagPostInline] 

admin.site.register(Post, PostAdmin) 

tham khảo: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-models

+1

Có, nhưng điều đó không thực sự làm những gì câu hỏi yêu cầu, đó là cho một widget [nhiều] chọn. –

23

Điều này có thể làm với một hình thức tùy chỉnh.

from django.contrib import admin 
from django import forms 

from models import Post, Tag 

class PostAdminForm(forms.ModelForm): 
    tags = forms.ModelMultipleChoiceField(
     Tag.objects.all(), 
     widget=admin.widgets.FilteredSelectMultiple('Tags', False), 
     required=False, 
    ) 

    def __init__(self, *args, **kwargs): 
     super(PostAdminForm, self).__init__(*args, **kwargs) 
     if self.instance.pk: 
      self.initial['tags'] = self.instance.tags.values_list('pk', flat=True) 

    def save(self, *args, **kwargs): 
     instance = super(PostAdminForm, self).save(*args, **kwargs) 
     if instance.pk: 
      instance.tags.clear() 
      instance.tags.add(*self.cleaned_data['tags']) 
     return instance 

class PostAdmin(admin.ModelAdmin): 
    form = PostAdminForm 

admin.site.register(Post, PostAdmin) 

Đó False trong đó có thể được thay thế bằng một True nếu bạn muốn theo chiều dọc xếp chồng lên nhau widget.

+1

Um ... Tôi có bỏ sót điều gì đó, hay điều này hoàn toàn thiếu điểm OP? Điểm là "danh sách các bài viết trong TagAdmin". TagAdmin, không phải PostAdmin. Cách tiếp cận có vẻ tốt mặc dù. – frnhr

+0

Có thể hoán đổi TagAdmin và PostAdmin. –

+0

Có thể. Ngoài ra, lưu sẽ không hoạt động theo cách này khi thêm một đối tượng mới, vì quản trị Django gọi nó bằng 'form.save (commit = False)', do đó không có pk. Thay vào đó, hãy di chuyển mã đó đến 'TagAdmin.save_model (...)'. – frnhr

4

Giải pháp của Matthew không hiệu quả đối với tôi (Django 1.7) khi tạo mục nhập mới, vì vậy tôi phải thay đổi một chút. Tôi hy vọng nó hữu ích cho một ai đó :)

class PortfolioCategoriesForm(forms.ModelForm): 
    items = forms.ModelMultipleChoiceField(
     PortfolioItem.objects.all(), 
     widget=admin.widgets.FilteredSelectMultiple('Portfolio items', False), 
     required=False 
    ) 

    def __init__(self, *args, **kwargs): 
     super(PortfolioCategoriesForm, self).__init__(*args, **kwargs) 
     if self.instance.pk: 
      initial_items = self.instance.items.values_list('pk', flat=True) 
      self.initial['items'] = initial_items 

    def save(self, *args, **kwargs): 
     kwargs['commit'] = True 
     return super(PortfolioCategoriesForm, self).save(*args, **kwargs) 

    def save_m2m(self): 
     self.instance.items.clear() 
     self.instance.items.add(*self.cleaned_data['items']) 
0

Sửa đổi mô hình của bạn để thêm lĩnh vực ngược lại:

# models.py 
from django.db import models 

class Post(models.Model): 
    title = models.CharField(max_length=100) 
    published_on = models.DateTimeField() 
    tags = models.ManyToManyField('Tag') 

class Tag(models.Model): 
    name = models.CharField(max_length=10) 
    posts = models.ManyToManyField('blog.Post', through='blog.post_tags') 

Sau đó, trong cách tiêu chuẩn thêm lĩnh vực để ModelAdmin:

#admin.py 
from django.contrib import admin 

class TagAdmin(admin.ModelAdmin): 
    list_filter = ('posts',) 

admin.site.register(Tag, TagAdmin) 
+0

Điều này phá vỡ di chuyển, syncdb vv Có một cách giải quyết hacky: https://djangosnippets.org/snippets/1295/ nhưng tôi đã không thử nó với di chuyển Django mới –

+0

Với Django 1,11, điều này thực sự hoạt động tốt bây giờ, như xa như tôi có thể nói. 'makemigrations' tạo ra một di chuyển cho trường M2M thừa, nhưng nó áp dụng mà không có vấn đề gì. –

Các vấn đề liên quan