以防万一其他人需要另一种方式来实现“追随者”,就像您所描述的那样,但具有不同的建模方案:
# 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):
class Meta:
# ...
username = models.CharField(...)
email = models.EmailField(...)
# ...
### Custom app-specific relationships (database scheme) ###
# symmetrical=False is needed for this reason: https://stackoverflow.com/a/42040848/3433137
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):
# ...
# new:
following = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Following',
is_stacked=False
)
)
# new:
followers = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Followers',
is_stacked=False
)
)
class Meta:
model = get_user_model()
# add 'following' and 'followers' to the fields:
fields = ('email', 'password', ..., 'following', 'followers')
# also needed to initialize properly:
def __init__(self, *args, **kwargs):
super(UserChangeForm, self).__init__(*args, **kwargs)
# Filter out the self user in the lists and initialize followers list:
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):
add_form = UserCreationForm
form = UserChangeForm
model = get_user_model()
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ['email', 'username', 'is_admin']
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('username',)}),
('Permissions', {'fields': ('is_admin', 'is_superuser', 'is_staff')}),
# new:
('Following / Followers', {'fields': ('following', 'followers')}),
)
# other fields
# ...
# new:
filter_horizontal = ('following', 'followers')
admin.site.register(User, Admin)
admin.site.unregister(Group)
如果然后启动服务器并转到 localhost:8000/admin/
并导航到用户的详细信息页面,您应该在屏幕上看到类似以下内容:
我没有添加计数器,因此您可以在列表视图中立即看到关注者的数量。
Note带有关注者的第二个 FormField 在管理面板中是只读的。用户不能选择其他用户关注他。