I'm trying to show user group name instead of it's id .
I have this serilizer class for user class and I used this User = auth.get_user_model() for user Model
but it show NULL instead of theier name .. when i delete get_groups function i will see related groups id why ?
what is correct way to get all users group?
class UserSerializer(ModelSerializer):
groups = SerializerMethodField()
def get_groups(self, obj):
return obj.groups.name
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'date_joined',
'last_login',
'is_staff',
'is_superuser',
'is_active',
'groups'
]
try it
groups = serializers.SlugRelatedField(many=True, read_only=True, slug_field="name")
Try this,
class UserSerializer(ModelSerializer):
def get_groups(self, obj):
return obj.groups.values_list('name', flat=True)
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'date_joined',
'last_login',
'is_staff',
'is_superuser',
'is_active',
'groups'
]
This would return all grups related to paricular user as list
Example:
In [5]: user =User.objects.get(id=1)
In [6]: user.groups.values_list('name',flat=True)
Out[6]: ['grp_name_1', 'grp_name_2']
In [8]: user.groups.all()
Out[8]: [<Group: grp_name_1>, <Group: grp_name_2>]
Related
I'm writing an API and I want to return a list of users along with the groups each user belongs to. I'm fairly new to Django and I'm stuck. I've tried several ways but the closest I came to finding a solution is when Django returned auth.Group.none while the user is in a Group.
authentication/models.py
class CustomUser(AbstractUser):
role = models.CharField(blank=True, max_length=120)
authentication/views.py
class CustomUserView(APIView):
permission_classes = [IsAuthenticated, IsAdmin, ]
serializer_class = CustomUserSerializer
def get(self, request, format='json'):
queryset = CustomUser.objects.all()
serializer = CustomUserSerializer(queryset, many=True)
filterset_fields = ['id', 'name', 'email', 'groups']
return Response(serializer.data, status=status.HTTP_200_OK)
authentication/serializers.py
class CustomUserSerializer(serializers.ModelSerializer):
email = serializers.CharField(
required=True
)
username = serializers.CharField(required=True)
password = serializers.CharField(min_length=8, write_only=True)
first_name = serializers.CharField()
last_name = serializers.CharField()
groups = serializers.CharField()
role = serializers.CharField()
class Meta:
model = CustomUser
fields = ('id', 'email', 'username', 'first_name', 'last_name', 'password', 'groups', 'role')
extra_kwargs = {'password': {'write_only': True}}
JSON Output
{
"id": 4,
"email": "",
"username": "testuser",
"first_name": "",
"last_name": "",
"groups": "auth.Group.None"
}
Any input would be appreciated!
Thanks in advance.
groups = serializers.CharField()
, in your serializer is incorrect , change serializer to this:
from django.contrib.auth.models import Group
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model= Group
fields = ('id','name')
class CustomUserSerializer(serializers.ModelSerializer):
email = serializers.CharField(required=True)
username = serializers.CharField(required=True)
password = serializers.CharField(min_length=8, write_only=True)
first_name = serializers.CharField()
last_name = serializers.CharField()
groups = GroupSerializer(many=True)
role = serializers.CharField()
class Meta:
model = CustomUser
fields = ('id', 'email', 'username', 'first_name', 'last_name', 'password','groups', 'role')
extra_kwargs = {'password': {'write_only': True}}
Zahra Ebrahimi's answer is correct, Its just an extension of the answer.
if you want to use drf's browsable api form to create the instance, then add a queryset of groups, for the conveniences.
class GroupSerializer(PrimaryKeyRelatedField,serializers.ModelSerializer):
class Meta:
model= Group
fields = ('id','name')
class CustomUserSerializer(serializers.ModelSerializer):
......
......
groups = GroupSerializer(many=True, queryset=Groups.objects.all())
......
class Meta:
model = CustomUser
fields = ('id', 'email', 'username', 'first_name', 'last_name', 'password','groups', 'role')
extra_kwargs = {'password': {'write_only': True}}
I created a customUser model so that the default User is overwritten.
This is my customUser model:
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
from crispy_forms.helper import FormHelper
class CustomUserCreationForm(UserCreationForm):
helper = FormHelper()
class Meta(UserCreationForm):
model = CustomUser
fields = ('first_name', 'username', 'email', 'last_name', 'organization', 'location', 'postcode', 'phone', 'agree_conditions')
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm):
model = CustomUser
fields = ('username', 'email', 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')
Everything works perfectly however I am not able to change the order of the "User default" fields.
I know how to re-order the form fields, I can simply change the order in the fields = (a, b, c). For example if I want "c" to appear before "a" and "b" in the form, I can do: fields = (c, a, b).
HOWVER I want to move up the password and password confirmation
but I do not know how to do so because I do know know their name in the User default model.
Ideally I want this:
fields = ('username', 'email', 'PASSWORD_WHICH_I_DONT_KNOW_THE_NAME', 'CONFIRMPASSWORD_WHICH_I_DONT_KNOW_THE_NAME' 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')
Solved, it was silly of me.
I inspected the HTML of the form and found out that:
the "PASSWORD_WHICH_I_DONT_KNOW_THE_NAME" is named by default: password1
The "CONFIRMPASSWORD_WHICH_I_DONT_KNOW_THE_NAME" is named by default: password2
So it will be:
fields = ('username', 'email', 'password1', 'password2' 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')
I am trying to assign current 'User' to two models using nested serializers.
class UserAddressSerializer(serializers.ModelSerializer):
class Meta:
model = UserAddress
fields = ('user', 'address_1', 'address_2', 'country',
'state_province', 'city', 'zip_code')
class UserProfileSerializer(serializers.ModelSerializer):
user_address = UserAddressSerializer()
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = UserProfile
fields = ('user', 'first_name', 'middle_name', 'last_name',
'title', 'display_name', 'time_zone', 'user_address', 'default_office')
def create(self, validated_data):
user = validated_data.pop('user')
user_address_data = validated_data.pop('user_address')
user_address_object = UserAddress.objects.create(
user=user, **user_address_data)
user_profile_object = UserProfile.objects.create(
user=user, **validated_data)
return user
What I am getting is this output in Postman.
{
"user_address": {
"user": [
"This field is required."
]
}
}
I want to know a way to pass 'User' to both of these model creation.
You need to remove user from fields of UserAddressSerializer:
class UserAddressSerializer(serializers.ModelSerializer):
class Meta:
model = UserAddress
fields = ('address_1', 'address_2', 'country', # <-- Here
'state_province', 'city', 'zip_code')
I'm trying to extend Django's django.contrib.auth.forms.UserCreationForm to include email and name fields. My similar extension of the UserChangeForm works fine, but UserCreationForm still only shows the default username, password1, and password2 fields. Any ideas what I'm doing wrong?
forms.py
class AuthorCreation(UserCreationForm):
class Meta:
model = User
fields = ('username', 'password1', 'password2',
'first_name', 'last_name', 'email', 'groups', 'is_staff')
class AuthorChange(UserChangeForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name',
'email', 'password', 'groups', 'is_staff')
admin.py
class AuthorAdmin(UserAdmin):
"""Admin class for creating and managing Authors"""
inlines = [AuthorInline]
fieldsets = (
(None, {
'fields': ('username', ('first_name', 'last_name'),
'email', 'password', 'groups', 'is_staff')
}),
)
class Media:
css = {
'all': [
'css/codenotes-admin.css',
]
}
def get_form(self, request, obj=None, **kwargs):
if obj is None:
return forms.AuthorCreation
else:
return forms.AuthorChange
admin.site.unregister(User)
admin.site.register(User, AuthorAdmin)
Again, the AuthorChangeForm correctly displays all the fields, but AuthorCreationForm only displays the username, password1, and password2 fields (plus the inline forms, which works fine on both).
I assume the problem is with the fieldsets, but I can't figure it out from the docs.
I figured out the solution. The problem was, as I suspected, the fieldsets. It turns out that the UserAdmin class inherits has TWO fieldsets that need to be overridden, fieldsets and add_fieldsets. I didn't see this mentioned anywhere in the docs (maybe I just missed it); I had to dig through the source to find it. As the name suggests, add_fieldsets is used when adding a new user. The following admin class works as expected:
admin.py
class AuthorAdmin(UserAdmin):
"""Admin class for creating and managing Authors"""
inlines = [AuthorInline]
fieldsets = (
(None, {
'fields': ('username', ('first_name', 'last_name'),
'email', 'password', 'groups', 'is_staff')
}),
)
add_fieldsets = (
(None, {
'fields': ('username', 'password1', 'password2',
('first_name', 'last_name'),
'email', 'groups', 'is_staff'),
}),
)
class Media:
css = {
'all': [
'css/codenotes-admin.css',
]
}
def get_form(self, request, obj=None, **kwargs):
if obj is None:
return forms.AuthorCreation
else:
return forms.AuthorChange
admin.site.unregister(User)
admin.site.register(User, AuthorAdmin)
From the Django doc:
class UserCreationForm¶ A ModelForm for creating a new user.
It has three fields: username (from the user model), password1, and
password2. It verifies that password1 and password2 match, validates
the password using validate_password(), and sets the user’s password
using set_password().
So it seems you have to create the extra fields yourself like this:
class AuthorCreation(UserCreationForm):
first_name = forms.CharField(required=True, label="First Name")
... etc ...
class Meta:
model = User
fields = ('username', 'password1', 'password2',
'first_name', 'last_name', 'email', 'groups', 'is_staff')
I have a custom user object GameUser, a profile UserInfo that attaches to each user with information, and a Weapon model that each profile gets associated to, but can only have one at a time.
I want to be able to look up and existing GameUser in my admin interface and, in the change form, have the option to create an associate a new Weapon to that UserInfo profile.
Here's my models:
class GameUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField()
# ...etc
class UserInfo(models.Model):
first = models.CharField(max_length=30)
last = models.CharField(max_length=30)
# ...etc
# relations
user = models.OneToOneField(GameUser)
weapon = models.ForeignKey('Weapon', null=True)
class Weapon(models.Model):
name = models.CharField(max_length=20)
# ...etc
And my admin.py:
class GameUserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
class Meta:
model = GameUser
fields = ('email', 'password')
def clean_password(self):
return self.initial["password"]
class GameUserAdmin(UserAdmin):
form = GameUserChangeForm
list_display = ('email', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Permissions', {'fields': ('is_admin',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
class UserInfoAdmin(admin.ModelAdmin):
fieldsets = [
('Personal Information', {'fields': [
'first', 'last']
}),
# ... etc
]
list_display = ('first', 'last')
search_fields = ['city', 'state']
admin.site.register(UserInfo, UserInfoAdmin)
admin.site.register(GameUser, GameUserAdmin)
If there is a Weapon associated with that GameInfo, I'd like to display it there inline. If not, I'd like to be able to create a new Weapon object for that GameInfo and set its fields.
I should mention I'm not married to Weapon being a ForiegnKey - it could certainly be a OneToOneField as well if that makes it easier.
What is the right way for me to do this in Django?