Views
class AuthDataViewSet(ModelViewSet):
queryset = AuthData.objects.all()
serializer_class = AuthDataSerializer
def create(self, request, *args, **kwargs):
serializer_data, headers = create_auth_data(self, request.data, {'request': request})
# returning response with the data
create_auth_data function
def create_response_data(view, data: dict = None, context: dict = None):
# I calling the viewset methods below
serializer = view.get_serializer(data=data, context=context)
serializer.is_valid(raise_exception=True)
view.perform_create(serializer)
headers = view.get_success_headers(serializer.data)
return serializer.data, headers
Serializer
class AuthDataSerializer(ModelSerializer):
class Meta:
model = AuthData
fields = ('login', 'password', 'project', 'manager')
def create(self, validated_data):
validated_data['manager'] = self.context['request'].user.manager
return validated_data
I got the correct serializer.data, no errors and pure data, but the instance didn't saved to the database.
Give this a try:
class AuthDataSerializer(ModelSerializer):
class Meta:
model = AuthData
fields = ('login', 'password', 'project', 'manager')
def create(self, validated_data):
auth_data = AuthData.objects.create(**validated_data)
return auth_data
Related
I am new in django and drf
in my project I have two group of permissions
1.normal_user group : with view_issue,view_project,view_analyzeissue
2.manager_user : with all permission as possible
i have some views that check some permissions
for example IssuesViewApi view, this view need to NormalUserPermissions
so i created new group with composition of permissions in my tests and send request to the view
my new group have view_issue,change_issue
when i send request to the IssuesViewApi i get 403 response
i have a NormalUserPermissions class
class NormalUserPermissions(permissions.BasePermission):
def has_permission(self, request: Request, view):
if request.user.has_perms(get_group_permissions("normal_user")):
return True
return False
class IssuesViewApi(generics.ListAPIView):
class IssueFilter(FilterSet):
labels = CharFilter(field_name="labels", lookup_expr='contains')
project_id = NumberFilter(field_name="project__id", lookup_expr='exact')
user_name = CharFilter(field_name="users__username", lookup_expr='exact')
start_date = DateFilter(field_name="updated_at", lookup_expr='gte')
end_date = DateFilter(field_name="updated_at", lookup_expr='lte')
class Meta:
model = Issue
fields = ["iid", 'is_analyzed', 'project_id', 'labels', 'user_name', 'start_date', 'end_date']
permission_classes = [IsAuthenticated, NormalUserPermissions]
http_method_names = ['get']
pagination_class = StandardPagination
queryset = Issue.objects.all()
serializer_class = IssueSerialize
filter_backends = [OrderingFilter, DjangoFilterBackend]
filterset_class = IssueFilter
ordering_fields = ['iid', 'weight'] # order fields depend on user request
ordering = ['iid'] # default order value
def get(self, request, *args, **kwargs):
response = super(IssuesViewApi, self).get(request, *args, **kwargs)
return Response({
'data': {
'issues': response.data['results'],
},
'paginationInfo': {
"count": response.data['count'],
"next_page": response.data['next'],
"previous_page": response.data['previous'],
"total_pages": self.paginator.page.paginator.num_pages
}
})
def test_create_custom_group_and_filter_issues_and_update_issue(self):
self.run_fake_discovery()
user = self.get_user()
user.groups.add(Group.objects.get_by_natural_key("manager_user"))
self.login(username=user.username, password="123456789")
add_group_url = reverse('group-add')
group_name = "new_group"
group_permissions = list(Permission.objects.filter(codename__in=['view_issue', 'change_issue']).all().values_list('id', flat=True))
response = self.client.post(add_group_url, data=json.dumps({'name': group_name, 'permissions': group_permissions}), content_type=self.CONTENT_TYPE)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(Group.objects.filter(name=group_name).exists())
sync_user_groups_url = reverse('sync-users-and-groups')
test_user = User.objects.get(username='testuser')
response = self.client.post(sync_user_groups_url, data=json.dumps({'group_name': group_name, 'users': [test_user.id]}), content_type=self.CONTENT_TYPE)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(test_user.groups.filter(name=group_name).exists())
response=self.logout()
self.assertEqual(response.status_code,status.HTTP_200_OK)
self.login(username=test_user.username, password='123456789')
filter_issue_url = reverse('issue-filter')
filter_issue_response = self.client.get(filter_issue_url, data={'username': user.username}, content_type=self.CONTENT_TYPE)
self.assertEqual(filter_issue_response.status_code, status.HTTP_200_OK)
Why all permissions checks ?
Im going to when user has view_issue permission then get response with 200 status
I created an extra function in my View that receives a list with hyperlinked references to some ResourceGroup objects, but I don't know how to convert them to database instances
class ResourceViewSet(viewsets.ModelViewSet):
queryset = Resource.objects.all()
serializer_class = ResourceSerializer
#action(methods=['put'], detail=True)
def groups_append(self, request, pk=None):
instance = self.get_object()
groups = request.data.get("groups")
for resource_group in groups:
instance.groups.add(WHAT_HERE(resource_group))
instance.save()
return Response(self.get_serializer(instance, many=False).data)
This is the request:
PUT http://.../api/resources/1/groups_append/
with body:
{"groups": ["http://.../api/resource_groups/1/", ...]}
ResourceSerializer:
class ResourceSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Resource
fields = ('resource_id', 'object_id', 'type', 'system', 'path', 'groups', 'job_set')
def update(self, instance, validated_data):
instance.object_id = validated_data.get('object_id', instance.object_id)
instance.type = validated_data.get('type', instance.type)
instance.system = validated_data.get('system', instance.system)
instance.path = validated_data.get('path', instance.path)
instance.save()
return instance
ResourceGroupSerializer:
class ResourceGroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ResourceGroup
fields = ('resource_group_id', 'label', 'resource_set')
def update(self, instance, validated_data):
instance.label = validated_data.get('label', instance.label)
instance.save()
return instance
use HyperlinkedRelatedField for groups in ResourceSerializer or just create a new serializer for this action(the main idea is to get the data using a serializers not just directly from the request body) like this:
class ResourceSerializer(serializers.HyperlinkedModelSerializer):
groups = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='groups-detail' ## name of the groups detail url
)
class Meta:
model = Resource
....
then edit your action as below:
#action(methods=['put'], detail=True)
def groups_append(self, request, pk=None):
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
### then get the groups from the validated data
groups = serializer.validated_data.get('groups', [])
....
....
References:
1- hyperlinkedrelatedfield
I want to set user_id field using JWT token and store in database table when new reservation is created. there can be single or multiple reservation request.
whenever user create reservation i want to store there user_id in our table. currently there is no foreign key associated with it. it is simply an integer field.
I am able to fetch user_id from JWT.but its not updating in database
I know this question had been asked previously i tried all the answer of previous post but its not working for me. i dont know why
model.py
class reservations(models.Model):
pet_id=models.IntegerField()
user_id=models.IntegerField(default=0)
location=models.PositiveSmallIntegerField()
arrival=models.DateTimeField()
depature=models.DateTimeField()
comments=models.TextField(max_length=200)
view.py
class requestReservation(CreateAPIView):
serializer_class = requestReservationSerailizer
permission_classes = [IsAuthenticated]
def create(self, request, *args, **kwargs):
serializer = requestReservationSerailizer(data=request.data,context={'user_id': request.user.id}, many=True)
if not serializer.is_valid(raise_exception=False):
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response({"message":"Success","status_message":"Reservation Created Successfully"},status=status.HTTP_200_OK)
serializer.py
class requestReservationSerailizer(ModelSerializer):
user_id = SerializerMethodField('set_user_id')
class Meta:
model=reservations
fields = [
'pet_id',
'user_id',
'location',
'arrival',
'depature',
'comments',
]
def set_user_id(self, obj):
obj.user_id = self.context.get("user_id")
return obj.user_id
currently it is simply storing user_id as 0 which is default set in model.
SerializerMethodField is read-only by default, here's a quick look at the source code:
def __init__(self, method_name=None, **kwargs):
self.method_name = method_name
kwargs['source'] = '*'
kwargs['read_only'] = True
super(SerializerMethodField, self).__init__(**kwargs)
Assuming you want to read and write into this field; remove the SerializerMethodField overriding from the serializer declaration; and set the user_id in your view
class requestReservationSerailizer(ModelSerializer):
class Meta:
model=reservations
fields = [
'pet_id',
'user_id',
'location',
'arrival',
'depature',
'comments',
]
def create(self, request, *args, **kwargs):
data = request.data.copy()
for datum in data:
datum['user_id'] = request.user.id
serializer = requestReservationSerailizer(data=data, many=True)
if not serializer.is_valid(raise_exception=False):
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response({"message":"Success","status_message":"Reservation Created Successfully"},status=status.HTTP_200_OK)
Ofcourse; if you don't want your view to be doing this (and I'd agree with you here), then pass it in context (explicit) or use self.request.user.id and override validate_user_id
class requestReservationSerailizer(ModelSerializer):
class Meta:
model=reservations
fields = [
'pet_id',
'user_id',
'location',
'arrival',
'depature',
'comments',
]
def validate_user_id(self, value):
user_id = self.context.get('user_id', None) # Assuming you continue to pass it in context
if user_id is None:
# Handle error
return user_id
# You can also do this; might raise an AttributeError if the user is not authenticated:
# return self.request.user.id
I have a profile model for user to update. I want to have a rest api for that. I have a profile model which is too big than usual. I am working to update the user profile but I am having confusion on which serializer should i use to update the profile. Here is what i have done till now
I created the serializer for user and user profile.
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('token', 'user','current_location', 'permanent_location', 'dob',
'about_me', 'gender_status', 'create_profile_for', 'marital_status',
'height', 'weight', 'body_type', 'complexion',)
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(required=True)
class Meta:
model = User
fields = ('id', 'profile', 'username', 'email', 'first_name', 'last_name',)
def update(self, instance, validated_data):
# instance = super(UserSerializer, self).update(validated_data)
profile_data = validated_data.pop('profile')
#updating user data
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.email = validated_data.get('first_name', instance.email)
#updating profile data
if not instance.profile:
Profile.objects.create(user=instance, **profile_data)
instance.profile.current_location = profile_data.get('current_location', instance.profile.current_location)
instance.profile.permanent_location = profile_data.get('permanent_location', instance.profile.permanent_location)
instance.profile.weight = profile_data.get('weight', instance.profile.weight)
instance.profile.height = profile_data.get('height', instance.profile.height)
instance.profile.about_me = profile_data.get('about_me', instance.profile.about_me)
instance.profile.create_profile_for = profile_data.get('create_profile_for', instance.profile.create_profile_for)
instance.profile.body_type = profile_data.get('body_type', instance.profile.body_type)
instance.save()
return instance
This is my view
class UserProfile(APIView):
serializer_class = UserSerializer
def get(self, request, token=None, format=None):
"""
Returns a list of profile of user
"""
reply={}
try:
profile_instance = Profile.objects.filter(user=self.request.user)
if token:
profile = profile_instance.get(token=token)
reply['data'] = self.serializer_class(profile).data
else:
reply['data'] = self.serializer_class(profile_instance, many=True).data
except:
reply['data']=[]
return Response(reply, status.HTTP_200_OK)
def post(self, request, token=None, format=None):
"""
update a profile
"""
profile=None
if not token is None:
try:
profile = Profile.objects.get(user=request.user, token=token)
except Profile.DoesNotExist:
return error.RequestedResourceNotFound().as_response()
except:
return error.UnknownError().as_response()
serialized_data = self.serializer_class(profile, data=request.data, partial=True)
reply={}
if not serialized_data.is_valid():
return error.ValidationError(serialized_data.errors).as_response()
else:
profile = serialized_data.save(user=request.user)
reply['data']=self.serializer_class(profile, many=False).data
return Response(reply, status.HTTP_200_OK)
How should i handle my user profile update?
Updated my UserSerializer with update function
UPDATE with Dean Christian Armada solution
class UserProfile(APIView):
serializer_class = ProfileSerializer
def get(self, request, token=None, format=None):
"""
Returns a list of profile of user
"""
reply={}
try:
profile_instance = Profile.objects.filter(user=self.request.user)
if token:
profile = profile_instance.get(token=token)
reply['data'] = self.serializer_class(profile).data
else:
reply['data'] = self.serializer_class(profile_instance, many=True).data
except:
reply['data']=[]
return Response(reply, status.HTTP_200_OK)
def put(self, request, token=None, *args, **kwargs):
"""
update a profile
"""
print('token', token)
if token:
try:
profile = Profile.objects.get(token=token)
except:
return Response(status=status.HTTP_400_BAD_REQUEST)
serialized_data = self.serializer_class(profile, data=request.data)
reply={}
if serialized_data.is_valid():
profile = serialized_data.save(user=request.user)
reply['data'] = self.serializer_class(profile, many=False).data
return Response(reply, status.HTTP_200_OK)
else:
return Response(serialized_data.errors, status.HTTP_400_BAD_REQUEST)
With your code, i get This QueryDict instance is immutable error
It's a standard to use the PUT request method for updating in your current code and situation it is better to use the ProfileSerializer since it has more fields. Also, the way I see it you only have three fields in the User object that can be changed and those three fields I assume is rarely changed.
views.py
def put(self, request, *args, **kwargs):
"""
update a profile
"""
data = request.data
print data
try:
profile = Profile.objects.get(token=data.get('token'))
except:
return Response(status=status.HTTP_400_BAD_REQUEST)
serializer = self.serializer_class(profile, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status.HTTP_200_OK)
else:
return Response(serializer.errors,
status.HTTP_400_BAD_REQUEST)
serializers.py
class ProfileSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Profile
fields = ('user', 'height', 'weight', 'token')
def to_internal_value(self, data):
first_name = data.pop('first_name', None)
last_name = data.pop('last_name', None)
data = super(ProfileSerializer, self).to_internal_value(data)
data['first_name'] = first_name
data['last_name'] = last_name
return data
def update(self, instance, validated_data):
first_name = validated_data.pop('first_name', None)
last_name = validated_data.pop('last_name', None)
user_inst_fields = {}
if first_name:
user_inst_fields['first_name'] = first_name
if last_name:
user_inst_fields['last_name'] = last_name
if user_inst_fields:
User.objects.update_or_create(pk=instance.user.id,
defaults=user_inst_fields)
profile, created = Profile.objects.update_or_create(
token=instance.token, defaults=validated_data)
return profile
Simply just set the user to read only for it to avoid validation
I am trying, through a CustomUser model and its serializer to register new users and to display them.
Here is my model:
class CustomUser(models.Model):
user = models.OneToOneField(User)
additional_field = models.CharField(max_length=30, default='', blank=True)
My serializer (from Django REST Framework Creating custom user):
class CustomUserSerializer(serializers.ModelSerializer):
additional_field = serializers.CharField(source='customuser.additional_field')
class Meta:
model = User
fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'additional_field')
def create(self, validated_data):
profile_data = validated_data.pop('customuser', None)
user = super(CustomUserSerializer, self).create(validated_data)
self.create_or_update_profile(user, profile_data)
return user
def update(self, instance, validated_data):
profile_data = validated_data.pop('customuser', None)
self.create_or_update_profile(instance, profile_data)
return super(CustomUserSerializer, self).update(instance, validated_data)
def create_or_update_profile(self, user, profile_data):
profile, created = CustomUser.objects.get_or_create(user=user, defaults=profile_data)
if not created and profile_data is not None:
super(CustomUserSerializer, self).update(profile, profile_data)
An my views, respectively to display and register a user:
def get_all_users(request):
all_friends = CustomUser.objects.all()
serial = CustomUserSerializer(all_friends, many=True)
json_data = JSONRenderer().render(serial.data)
return HttpResponse(json_data, content_type='application/json')
#api_view(['POST'])
def register_new_user(request):
if request.method == 'POST':
print('POST request !')
print(request.data)
serializer = CustomUserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
print('save friend!')
return HttpResponse(status.HTTP_201_CREATED)
else:
print(serializer.errors)
return HttpResponse(status.HTTP_403_FORBIDDEN)
While I am able to register a user with the following piece of code:
import requests
import json
json_data = {'username': 'mylogin99', 'password': 'mypassword', 'email': 'mymail99#wanadoo.fr', 'additional_field' : 'myaddfield'}
r = requests.post('http://127.0.0.1:8000/register_new_user', json=json_data)
I am unable to display the registered users, as I get the following error:
AttributeError at /getAllUsers
Got AttributeError when attempting to get a value for field `username` on serializer `CustomUserSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `CustomUser` instance.
Original exception text was: 'CustomUser' object has no attribute 'username'.
I do not understand why the username field does not refer to the username field of the User model.
The best way I could come up with was to implement a as_json method in the CustomUser model:
def as_json(self):
return dict(
id=self.user.id, username=self.user.username,
password=self.user.password, email=self.user.email,
additional_field=self.additional_field)
Thus, to retrieve all the registered users, I've modified the get_all_user method:
#api_view(['GET'])
def get_all_users(request):
# retrieve all CustomUser objects
all_friends = CustomUser.objects.all()
lst = [friend.as_json() for friend in all_friends]
json_data = JSONRenderer().render(lst)
return HttpResponse(json_data, content_type='application/json')