I copied https://pypi.python.org/pypi/fh-drf-friendship/0.1.1 (Because i don't know how to apply fh-drf-friendship on my project.)
views.py
class FriendViewSet(NestedViewSetMixin, mixins.ListModelMixin, mixins.CreateModelMixin,
mixins.DestroyModelMixin, viewsets.GenericViewSet):
serializer_class = UserSerializer
def create(self, request, *args, **kwargs):
request.data['to_user'] = self.get_parents_query_dict()['user']
serializer = FriendSerializer(data=request.data)
if serializer.is_valid():
instance = serializer.save()
headers = self.get_success_headers(serializer.data)
serializer = FriendReadSerializer(instance)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_object(self):
to_user = User.objects.get(pk=self.get_parents_query_dict().get('user'))
from_user = User.objects.get(pk=self.kwargs.get('pk'))
return Friend.objects.get(to_user=to_user, from_user=from_user)
serializers.py
class UserSerializer(serializers.ModelSerializer):
related_postwriter = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
related_commentwriter = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = User
fields = ('id', 'username', 'email', 'related_postwriter', 'related_commentwriter')
class FriendSerializer(rest_framework_common.serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(source='from_user', queryset=User.objects.all())
class Meta:
model = Friend
exclude = ('url', 'from_user',)
def create(self, validated_data):
fr = FriendshipRequest.objects.get(from_user=validated_data['from_user'], to_user=validated_data['to_user'])
if fr and fr.accept():
return Friend.objects.get(from_user=validated_data['from_user'], to_user=validated_data['to_user'])
class FriendReadSerializer(rest_framework_common.serializers.ModelSerializer):
user = UserSerializer(source='from_user')
created_at = serializers.DateTimeField(source='created')
class Meta:
model = Friend
exclude = ('url', 'from_user', 'to_user', 'created',)
django version == 1.9.7
django rest framework version == 3.4.1
python3 == 3.5
On urls.py, there are router.register(r'friend', views.FriendViewSet, base_name='friend')
And when i go http://127.0.0.1:8000/friend/ on web browser,
DoesNotExist at /friend/
User matching query does not exist. comes.
How can i solve it?
Related
If I need to change some field values before saving to the database as I think models method clear() is suitable. But I can't call him despite all my efforts.
For example fields email I need set to lowercase and fields nda I need set as null
models.py
class Vendors(models.Model):
nda = models.DateField(blank=True, null=True)
parent = models.OneToOneField('Vendors', models.DO_NOTHING, blank=True, null=True)
def clean(self):
if self.nda == "":
self.nda = None
class VendorContacts(models.Model):
....
vendor = models.ForeignKey('Vendors', related_name='contacts', on_delete=models.CASCADE)
email = models.CharField(max_length=80, blank=True, null=True, unique=True)
def clean(self):
if self.email:
self.email = self.email.lower()
serializer.py
class VendorContactSerializer(serializers.ModelSerializer):
class Meta:
model = VendorContacts
fields = (
...
'email',)
class VendorsSerializer(serializers.ModelSerializer):
contacts = VendorContactSerializer(many=True)
class Meta:
model = Vendors
fields = (...
'nda',
'contacts',
)
def create(self, validated_data):
contact_data = validated_data.pop('contacts')
vendor = Vendors.objects.create(**validated_data)
for data in contact_data:
VendorContacts.objects.create(vendor=vendor, **data)
return vendor
views.py
class VendorsCreateView(APIView):
"""Create new vendor instances from form"""
permission_classes = (permissions.AllowAny,)
serializer_class = VendorsSerializer
def post(self, request, *args, **kwargs):
serializer = VendorsSerializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
serializer.save()
except ValidationError:
return Response({"errors": (serializer.errors,)},
status=status.HTTP_400_BAD_REQUEST)
else:
return Response(request.data, status=status.HTTP_200_OK)
As I learned from the documentation
Django Rest Framework serializers do not call the Model.clean when
validating model serializers
In dealing with this problem, I found two ways to solve it.
1. using the custom method at serializer. For my case, it looks like
class VendorsSerializer(serializers.ModelSerializer):
contacts = VendorContactSerializer(many=True)
class Meta:
model = Vendors
fields = (...
'nda',
'contacts',
)
def create(self, validated_data):
contact_data = validated_data.pop('contacts')
vendor = Vendors.objects.create(**validated_data)
for data in contact_data:
VendorContacts.objects.create(vendor=vendor, **data)
return vendor
def validate(self, attrs):
instance = Vendors(**attrs)
instance.clean()
return attrs
Using full_clean() method. For me, it looks like
class VendorsSerializer(serializers.ModelSerializer):
contacts = VendorContactSerializer(many=True)
class Meta:
model = Vendors
fields = (...
'nda',
'contacts',
)
def create(self, validated_data):
contact_data = validated_data.pop('contacts')
vendor = Vendors(**validated_data)
vendor.full_clean()
vendor.save()
for data in contact_data:
VendorContacts.objects.create(vendor=vendor, **data)
return vendor
But in both cases, the clean() method is not called. I really don't understand what I'm doing wrong.
In my case I had the same problem but with validation feature
I used the way below and it works for me (not excludes the way found above):
class CustomViewClass(APIView):
def post(self, request, format=None):
prepared_data_variable = 'some data in needed format'
serializer = CustomSerializer(data=request.data)
if serializer.is_valid(self):
serializer.validated_data['field_name'] = prepared_data_variable
serializer.save()
return Response(data=serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
This string is key for my solution serializer.validated_data['field_name'] = prepared_data_variable
For DRF you can change your serializer before save as below...
First of all, you should check that serializer is valid or not, and if it is valid then change the required object of the serializer and then save that serializer.
if serializer.is_valid():
serializer.object.user_id = 15 # For example
serializer.save()
UPD!
views.py
class VendorsCreateView(APIView):
"""Create new vendor instances from form"""
permission_classes = (permissions.AllowAny,)
serializer_class = VendorsSerializer
def post(self, request, *args, **kwargs):
data = request.data
if data['nda'] == '':
data['nda'] = None
for contact in data['contacts']:
if contact['email']:
print(contact['email'])
contact['email'] = contact['email'].lower()
serializer = VendorsSerializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
serializer.save()
except ValidationError:
return Response({"errors": (serializer.errors,)},
status=status.HTTP_400_BAD_REQUEST)
To answer your question: just override save() method for your models as written in docs. There you can assign any values to your model instance directly before saving it in database.
Also, you should probably use models.EmailField for your email fields which will get rid of your lower() check.
I have a below view, serializer and model. Using BrowsableAPIRenderer i render HTML page. I need to assign current user id to user_id field and hide the same from HTML rendering(not allow to edit and enter). I am using Django rest framework 2.3.13. Kindly help me to achieve this.
serializer.py
class TagOwnerSerializer(serializers.HyperlinkedModelSerializer):
tag_id = serializers.SlugRelatedField(slug_field='tag_id')
user_id = serializers.IntegerField(write_only=True)
class Meta:
model = TagOwner
fields = ('url','tag_id','start_time','end_time','user_id')
views.py
class TagOwnerViewSet(viewsets.ModelViewSet):
"""
TagOwner table view set.
"""
model = TagOwner
queryset = TagOwner.objects.all()
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
serializer_class = TagOwnerSerializer
renderer_classes = (BrowsableAPIRenderer, JSONRenderer,JSONPRenderer,XMLRenderer,YAMLRenderer)
filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter ,filters.OrderingFilter)
filter_class = TagOwnerFilter
#search_fields = ('tag_id',)
ordering_fields = '__all__'
def get_queryset(self):
user = self.request.user
if self.request.user.is_authenticated():
if not user:
return []
return TagOwner.objects.filter(user_id=user.id)
public_tags = TagReads.objects.filter(public=True).values_list('tag_id').distinct()
return TagOwner.objects.filter(tag_id__in=public_tags)
def create(self,request):
serializer = self.serializer_class(data=request.DATA)
if serializer.is_valid():
user=self.request.user.id
serializer.save(user_id = user)
return Response(serializer.data, status = status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
models.py
class TagOwner(models.Model):
user_id = models.IntegerField(blank=False,db_column='user_id',)
tag_id = models.OneToOneField('Tags',on_delete=models.CASCADE,primary_key=True,db_column='tag_id',)
start_time = models.DateTimeField(blank=True, null=True)
end_time = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tag_owner'
Found it myself.
serializer.py
class TagOwnerSerializer(serializers.HyperlinkedModelSerializer):
tag_id = serializers.SlugRelatedField(slug_field='tag_id')
user_id = serializers.Field(source='user_id')
#user_id = serializers.PrimaryKeyRelatedField(read_only=True,default=serializers.CurrentUserDefault())
class Meta:
model = TagOwner
fields = ('url','tag_id','start_time','end_time','user_id')
views.py
class TagOwnerViewSet(viewsets.ModelViewSet):
"""
TagOwner table view set.
"""
model = TagOwner
queryset = TagOwner.objects.all()
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
serializer_class = TagOwnerSerializer
renderer_classes = (BrowsableAPIRenderer, JSONRenderer,JSONPRenderer,XMLRenderer,YAMLRenderer)
filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter ,filters.OrderingFilter)
filter_class = TagOwnerFilter
#search_fields = ('tag_id',)
ordering_fields = '__all__'
def get_queryset(self):
user = self.request.user
if self.request.user.is_authenticated():
if not user:
return []
return TagOwner.objects.filter(user_id=user.id)
public_tags = TagReads.objects.filter(public=True).values_list('tag_id').distinct()
return TagOwner.objects.filter(tag_id__in=public_tags)
def pre_save(self, obj):
obj.user_id = self.request.user.id
This worked perfectly for me.
I have UserProfile model that contains phone, profile_photo and some fields of Django default User model like first_name, last_name, email and I am trying to update some of these fields.
models.py
class UserProfile(models.Model):
user = models.ForeignKey(User, verbose_name="User")
phone = models.CharField(max_length=16, verbose_name="Phone")
profile_photo = models.ImageField(null=True, blank=True, upload_to=user_directory_path, verbose_name="Profile Photo")
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('url', 'first_name', 'last_name', 'email')
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(partial=True)
class Meta:
model = UserProfile
fields = '__all__'
def create(self, validated_data):
user_profile = UserProfile.objects.create(**validated_data)
return user_profile
views.py
class UserProfileViewSet(viewsets.ModelViewSet):
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
authentication_classes = (TokenAuthentication,)
#detail_route(methods=['PATCH'], url_path='update-partial')
def user_profile_update_partial(self, request, pk=None):
profile = UserProfile.objects.get(id=pk)
serializer = self.get_serializer(profile, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
If I send profile_photo, phone, first_name or last_name data with this #detail_route I am only able to update phone and profile_photo fields. Also getting Bad Request error when profile_photo data not sending.
How can I implement the partial_update with PATCH method?
class UserProfileViewSet(viewsets.ModelViewSet):
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
authentication_classes = (TokenAuthentication,)
def partial_update(self, request, *args, **kwargs):
profile = self.get_object()
serializer = self.get_serializer(profile, data=request.data, partial=True)
if serializer.is_valid():
user_serializer = UserSerializer(profile.user, data=request.data, partial=True)
if user_serializer.is_valid():
user_serializer.save()
serializer.save()
return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
else:
return Response(data=user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
return Response(data=serializer.errors,status=status.HTTP_400_BAD_REQUEST)
Q1:How to implement PATCH method?
A1:Override partial_update method.
Q2:How to update first_name or last_name?
A2:Update it with another Serializer named UserSerializer.(If you want update password,you need use make_password method to create encoded password before save raw password to database)
I'm new in Django and DRF and I'm trying to create a new user through POST request. I send the username and password parameters but django doesn't identify the parameters inside the POST request.
My serializer:
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user=get_user_model().objects.create(
username = validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
class Meta:
model = get_user_model()
fields = ('username', 'password')
My view class:
class CreateUserView(CreateAPIView):
model = get_user_model()
permission_classes = (AllowAny,)
serializer_class = UserSerializer
I have tried to use serializers.ModelSerializer and serializer.Serializers but don't have success.
class UserSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = UserModel.objects.create_user(**validated_data)
return user
class Meta:
model = YOUR_MODEL
fields = ('username', 'password',)
class CreateUserView(CreateAPIView):
model = YOUR_MODEL.objects.all()
permission_classes = (AllowAny,)
serializer_class = UserSerializer
You can do View as this and check your errors.
view.py
class CreateUser(APIView):
permission_classes = (AllowAny,)
def post(self, request):
post_data = request.data
print post_data # See what is your post DATA
serializer = UserSerializer(data=post_data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(data={'user':serializer.data})
return Response(data={'user':serializer.errors})
I'm building a REST web service, the GET method seems to be working all right
but when it comes to POST error message always shows up:
'dict' object has no attribute 'save'
models.py
from django.db import models
class Users(models.Model):
Fullname = models.CharField(max_length=50)
Username = models.CharField(max_length=15)
Password = models.CharField(max_length=8)
Email = models.CharField(max_length=50, unique=True)
Type = models.CharField(max_length=5)
TwitterName = models.CharField(max_length=15, unique=True)
FacebookName = models.CharField(max_length=15, unique=True)
CreationDate = models.DateTimeField()
serializer.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = ('Fullname', 'Username', 'Email', 'Password', 'Type', 'TwitterName', 'FacebookName')
views.py
#api_view(['GET', 'POST'])
def users_list(request, format=None):
if request.method == 'GET':
users = Users.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = UserSerializer(request.DATA, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)
I'm using PyCharm and Django 1.7
If you want to save the POST data then you should pass the data to data keyword argument:
serializer = UserSerializer(data=request.DATA, many=True)
if serializer.is_valid():
...
Also I would suggest you to use Class based views with Mixins as that will make your code much cleaner and shorter:
from rest_framework import generics, mixins
class UserList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Users.objects.all()
serializer_class = UserSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)