我在django-admin的ModelMultipleChoiceField
工作下得到了ManyToMany字段:
当我从左侧向右侧添加一个元素并在管理UI中单击“保存”,然后重新加载显示此ModelMultipleChoiceField
的详细信息页面时,可以清楚地看到已保存的元素在右侧。
此工作模型的代码如下:
# project/account/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from model_utils import Choices
class User(AbstractBaseUser, PermissionsMixin):
following = models.ManyToManyField('self', related_name='followers', blank=True, symmetrical=False)
# project/account/forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.admin.widgets import FilteredSelectMultiple
from .models import User
class UserChangeForm(forms.ModelForm):
following = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Following',
is_stacked=False
)
)
followers = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Followers',
is_stacked=False
)
)
class Meta:
model = get_user_model()
fields = ('following', 'followers')
def __init__(self, *args, **kwargs):
super(UserChangeForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk:
self.fields['following'] = forms.ModelMultipleChoiceField(
queryset=User.objects.all().exclude(pk=self.instance.pk),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Following',
is_stacked=False
)
)
self.fields['followers'] = forms.ModelMultipleChoiceField(
queryset=User.objects.all().exclude(pk=self.instance.pk),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Followers',
is_stacked=False
)
)
self.fields['followers'].initial = self.instance.followers.all()
# project/account/admin.py
from django.contrib.auth import get_user_model
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User
from .forms import UserChangeForm, UserCreationForm
class Admin(BaseUserAdmin):
form = UserChangeForm
model = get_user_model()
fieldsets = (
('Following / Followers', {'fields': ('following', 'followers')}),
)
admin.site.register(User, Admin)
admin.site.unregister(Group)
这将按预期将修改后的配置保存在管理面板中。
但是现在我有了另一个用例,在该用例中,我想为同一模型使用三个不同的ModelMultipleChoiceField
:
# project/account/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from model_utils import Choices
from shared_models.models import Badge
class User(AbstractBaseUser, PermissionsMixin):
badges = models.ManyToManyField(Badge, related_name='owners', blank=True)
# project/shared_models/models.py
from django.db import models
from model_utils import Choices
class Badge(models.Model):
BADGE_TYPES = Choices('bronze', 'silver', 'gold')
type = models.CharField(choices=BADGE_TYPES, max_length=10)
description = models.CharField(blank=False, max_length=1500)
class Meta:
app_label = 'shared_models'
def __set__(self, instance, value):
self.description = value
# project/account/forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.admin.widgets import FilteredSelectMultiple
from shared_models.models import Badge
from .models import User
def general_model_multiple_choice_field_filter_type(model, verbose_name, filter_by_type):
queryset = model.objects.all()
if filter:
queryset = queryset.filter(type=filter_by_type)
return forms.ModelMultipleChoiceField(
queryset=queryset,
required=False,
widget=FilteredSelectMultiple(
verbose_name=verbose_name,
is_stacked=False
)
)
class UserChangeForm(forms.ModelForm):
bronze_badges = general_model_multiple_choice_field_filter_type(model=Badge, verbose_name='Bronze Badges', filter_by_type='bronze')
silver_badges = general_model_multiple_choice_field_filter_type(model=Badge, verbose_name='Silver Badges', filter_by_type='silver')
gold_badges = general_model_multiple_choice_field_filter_type(model=Badge, verbose_name='Gold Badges', filter_by_type='gold')
class Meta:
model = get_user_model()
fields = ('bronze_badges',
'silver_badges',
'gold_badges')
def __init__(self, *args, **kwargs):
super(UserChangeForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk:
self.fields['bronze_badges'] = general_model_multiple_choice_field_filter_type(Badge,
'Bronze Badges',
filter_by_type='bronze')
self.fields['silver_badges'] = general_model_multiple_choice_field_filter_type(Badge,
'Silver Badges',
filter_by_type='silver')
self.fields['gold_badges'] = general_model_multiple_choice_field_filter_type(Badge,
'Gold Badges',
filter_by_type='gold')
# project/account/admin.py
from django.contrib.auth import get_user_model
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User
from django.db.models import Q
from .forms import UserChangeForm, UserCreationForm
class Admin(BaseUserAdmin):
form = UserChangeForm
model = get_user_model()
fieldsets = (
('Badges', {'fields': ('bronze_badges', 'silver_badges', 'gold_badges')}),
)
admin.site.register(User, Admin)
admin.site.unregister(Group)
但是现在,当我尝试向UI元素的“选择”部分添加徽章时,单击“保存”,重新加载页面,所选项目仍在左侧,右侧将保留空的。该帖子请求回复了302。
那我怎样才能让django保存对User.badges字段的修改?
编辑发现了一个完全可以满足我需要的问题:Is there a model MultiField (any way to compose db models Fields in Django)? Or why would not that be a useful concept?