Cannot query "object": Must be "User" instance - django

I am creating sample-api which have posts and followers. Post should visible to followers only
My models.py
from django.contrib.auth.models import User
class Post(models.Model):
creator = models.ForeignKey(User, related_name='creator_post_set', null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=25)
created_date = models.DateTimeField(auto_now_add=True)
content = models.TextField()
likes = models.BigIntegerField(null=True)
comments = models.BigIntegerField(null=True)
class Follow(models.Model):
follower = models.ForeignKey(User, related_name='following', null=True, on_delete=models.CASCADE)
followed_on = models.DateTimeField(auto_now_add=True)
following = models.ForeignKey(User, related_name='follower',null=True, on_delete=models.CASCADE)
My serializers.py for the models:
class UserSerializer(ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
password=validated_data['password'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
)
return user
class Meta:
model = User
fields = ('password', 'username', 'first_name', 'last_name',)
class PostListSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['title', 'content', 'created_date',]
class FollowSerializer(serializers.ModelSerializer):
class Meta:
model = Follow
fields = '__all__'
My views.py:
class PostList(generics.ListCreateAPIView):
serializer_class = PostListSerializer
follow_model = FollowSerializer.Meta.model
post_model = PostSerializer.Meta.model
def get_queryset(self):
try:
followers = self.follow_model.objects.get(follower_id =
self.request.user.id)
queryset = self.post_model.objects.get(creator__in = followers)
except self.follow_model.DoesNotExist:
queryset = None
return queryset
When I call this view it returns the following error:
Cannot query "Follow object (1)": Must be "User" instance.
I need help Thanks in Advance.

As I can see, Post model's creator is FKed to User model. So you need to query using User model instance, not Follower model.
You can use the following code:
following = self.request.user.following.all().values_list('follower', flat=True) # because of related name
queryset = self.post_model.objects.filter(creator_id__in = list(following))
Here I have first retrieved the user ids using self.request.following.all() by reverse relationship. Then I have extracted the user ids using values_list. After that, I have used it in Post.objects.filter(...) method.

Related

retrieving the last instance of a model in another model's modelSerializer in django rest framework

I am creating rest APIs for a website in which users can purchase one of the provided subscriptions.
In this website there is a user-info API which returns the information about the logged in user which can be used to show their info on the website.
The problem is that, the mentioned API's serializer is a modelSerializer on the "User" model and the information that I want to return is the instance of "Subscription" model which the latest instance of "SubPurchase" model refers to.
These are my serializers, models and views.And I need to somehow return the user's current subscription's ID and name along with the user's information. If you have any further questions, ask me in the comments and I'll answer them.
# models.py
class User(AbstractBaseUser, PermissionsMixin):
userID = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
email= models.EmailField(max_length=100, unique=True, validators=[EmailValidator()])
name = models.CharField(max_length=100)
isSuspended = models.BooleanField(default=False)
isAdmin = models.BooleanField(default=False)
emailActivation = models.BooleanField(default=False)
balance = models.IntegerField(default=0)
objects = UserManager()
USERNAME_FIELD = 'username'
class Subscription(models.Model):
subID = models.AutoField(primary_key=True)
nameOf = models.CharField(max_length=50)
price = models.PositiveIntegerField()
salePercentage = models.PositiveIntegerField(default=0)
saleExpiration = models.DateTimeField(default=datetime.datetime.now, blank=True)
def __str__(self):
return f"{self.nameOf}"
class SubPurchase(models.Model):
price = models.PositiveIntegerField()
dateOf = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
subscription = models.ForeignKey(Subscription, null=True, on_delete=models.SET_NULL)
def __str__(self):
return self.subscription
# serializers.py
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
# views.py
class UserInfoViewSet(viewsets.ModelViewSet):
queryset = get_user_model().objects.all()
serializer_class = UserInfoSerializer
def get_queryset(self):
uID = getattr(self.request.user,'userID')
return get_user_model().objects.filter(userID=uID)
def get_object(self):
uID = getattr(self.request.user,'userID')
return self.queryset.filter(userID=uID)
Again, I need to change the UserInfoSerializer in a way that would give me the user's current subscription's name, ID and expiration date which would be 30 days after the purchase date
If you are only interested in the returned data, you can override the function to_representation of your serializer and create a serializer for your related model. If I understood correctly, the current subscription of your user is the last one (if sorted by "dateOf"). So something like that could do the trick
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields = ('nameOf', 'id', 'saleExpiration ')
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
def to_representation(self, instance):
data = super().to_representation(instance)
current_subs = instance.subpurchase_set.order_by('dateOf').last().subscription
data['current_subscription'] = SubscriptionSerializer(instance=current_subs).data
return data
you can use NestedSerializers to achieve what you are looking for
basically, nested serialization is a method in which you can return, create, put..., into a model from another model, it goes like this..
models.py
class User(AbstractBaseUser, PermissionsMixin):
....
#user model data
class SubPurchase(models.Model):
...
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
serializers.py
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields =["anyfield you wanna include"]
class SubPurchaseSerializer(serializers.ModelSerializer):
class Meta:
model = SubPurchase
fields =["anyfield you wanna include"]
class UserInfoSerializer(serializers.ModelSerializer):
subpurchace = SubPurchaseSerializer()
subscription= SubscriptionSerializer() #later included in the fields of this serializer
class Meta:
model = get_user_model()
fields = ('userID','subpurchace', 'subscription', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')

how to add current active user as foreign key to the create post model in djangorestframework?

how to add current active user as foreign key to the create post model in djangorestframework ?
models:
class DoctorProfile(AbstractBaseUser, PermissionsMixin):
id=models.AutoField(primary_key=True)
name = models.CharField(_('name'), max_length=50, blank=True)
mobile = models.CharField(_('mobile'), unique=True, max_length=10, blank=False)
email = models.EmailField(_('email address'), blank=True)
password = models.CharField(_('password'),max_length=25,blank=False)
otp = models.IntegerField(null=True, blank=True)
class Doctor_clinic(models.Model):
clinic_id = models.AutoField(primary_key=True)
doc_profile = models.ForeignKey(DoctorProfile,on_delete=models.CASCADE)
clinic_name = models.CharField(max_length=150)
clinic_address = models.CharField(max_length=150)
City = models.CharField(max_length=50)
state = models.CharField(max_length=50)
pincode = models.IntegerField()
#how to get the forign key in serializers
I wrote in this way, is this correct/relevent?
class UserSerializer(serializers.ModelSerializer):
# mobile = serializers.RegexField("[0-9]{10}",min_length=10,max_length=10)
password = serializers.CharField(write_only=True)
email=serializers.EmailField(max_length=155,min_length=3,required=True)
name=serializers.CharField(max_length=55,min_length=3,required=True)
class Meta:
model = DoctorProfile
fields = ("name", "email", "password", "mobile","otp")
class ClinicSerializer(serializers.ModelSerializer):
class Meta:
model = Doctor_clinic
fields =('clinic_name','clinic_address', 'City', 'state', 'pincode','doc_profile')
views:
class ClinicRegistrationView(generics.ListCreateAPIView):
serializer_class = ClinicSerializer
queryset = Doctor_clinic.objects.all()
permission_classes = (IsAuthenticated,)
When serializing relations you need to define a seperate field depending on the representation you want, for example write your serializer like this:
class ClinicSerializer(serializers.ModelSerializer):
doc_profile = serializers.StringRelatedField()
class Meta:
model = Doctor_clinic
fields =('clinic_name','clinic_address', 'City', 'state', 'pincode','doc_profile')
permissions.py
use permission classes
class IsOwner(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.doc_profile == request.user
views.py
def perform_create(self, serializer):
return serializer.save(doc_profile=self.request.user)

How to add a foreign key to the username. Django REST framework

During serialization, i noticed that the post_author Foreign Key of the Post model is referencing the id of the creator and thus, i can't display the username of the creator in the REST API, only the post_author id.
How can i add the username of the post_creator, so that it is readable to other users, when i fetch the data on the frontend?
models.py // CustomUser = the Creator of the post.
class CustomUser(AbstractUser):
fav_color = models.CharField(blank=True, max_length=120)
class Post(models.Model):
post_author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='posts')
post_title = models.CharField(max_length=200)
post_body = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.post_title
views.py
#api_view(['GET'])
def post_list(request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return Response(serializer.data)
serializers.py user model and post model serialization
class CustomUserSerializer(serializers.ModelSerializer):
"""
Currently unused in preference of the below.
"""
email = serializers.EmailField(required=True)
username = serializers.CharField()
password = serializers.CharField(min_length=8, write_only=True)
class Meta:
model = CustomUser
fields = ('email', 'username', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
password = validated_data.pop('password', None)
# as long as the fields are the same, we can just use this
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
single post from the API
{
"id": 1,
"post_title": "first_post",
"post_body": "qwe1",
"created_date": "2020-11-17T19:30:55Z",
"published_date": null,
"post_author": 1
},
You need to override the serializer:
class PostSerializer(serializers.ModelSerializer):
post_author_username = serializers.ReadOnlyField(source="post_author.username")
class Meta:
model = Post
fields = [post_author_username, post_title, post_body, created_data, published_data]
You can to specify the post_author serializer in your PostSerializer:
class PostSerializer(serializers.ModelSerializer):
post_author=CustomUserSerializer(read_only=True)
class Meta:
model = Post
fields = '__all__'
You can see the documentation here

How to update Foreign key field using nested serializer in django

I am facing one issue for updating models using django serializer.
Here is my models:
class User(models.Model):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
designation = models.CharField(max_length=200, blank=True)
contact_number = models.CharField(max_length=20, blank=True)
team = models.CharField(max_length=200, blank=True)
manager = models.CharField(max_length=200, blank=True)
joining_date = models.DateField(default=datetime.now)
I need to create a serializer for editing profile details of the current user. In this User details like designation, contact_number , team , manager, joining_date are in UserProfile model and te first_name and last_name are in User model .... At one edit both the models needs to get update
This is my serializer.
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name','last_name')
class UserProfileSerializer(ModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = ('id', 'designation', 'contact_number', 'team', 'manager',
'joining_date','user')
def update(self, instance, validated_data):
user = validated_data.get('user')
instance.user.first_name = user.get('first_name')
instance.user.save()
return instance
I am getting an error {
"user": [
"This field is required."
]
}
Change user field to DictField. In this way, it will not be treated as foreignkey.
In to_representation, serialize user object and you will get data in format in which you want to get.
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name','last_name')
class UserProfileSerializer(ModelSerializer):
user = serializer.DictField(required=False, write_only=True, default={})
def to_representation(self, instance):
data = super().to_representation(instance)
data.update({'user': UserSerializer(instance.user).data})
return data
class Meta:
model = UserProfile
fields = ('id', 'designation', 'contact_number', 'team', 'manager',
'joining_date','user')
def update(self, instance, validated_data):
user = validated_data.get('user')
instance.user.first_name = user.get('first_name')
instance.user.save()
return instance

Nested API View of Django REST Framework?

At the moment I developed the following code, for me to get the Contact List of each user. The views return the ID numbers of the Contacts of the User. I need to get, instead of the ID numbers, the 'name' and 'last_name' attribute of said contacts. I am quite new to Django's REST Framework and I'm not quite sure what to do next but I believe I have to nest the APIView. I would really appreciate some help!
views.py
def list_contacts(request, id_profile):
url = request.build_absolute_uri(reverse('api_users:contact_list', kwargs={'pk':id_profile}))
response = requests.get(url)
profile = Profile.objects.get(pk=id_profile)
if response.status_code == status.HTTP_200_OK:
data = response.content
user = json.loads(data)
return render(request, 'profiles/contact_list.html', {'user':user})
models.py
class Profile(models.Model):
id_user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birthday = models.DateField(auto_now=False)
description = models.CharField(max_length=100)
profile_picture = models.ImageField(upload_to='images/profiles/%Y/%m/%d', blank=False)
active = models.BooleanField(default = False)
contacts = models.ManyToManyField('self', blank=True, default='null')
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(default=timezone.now)
deleted_at = models.DateTimeField(blank=True, null=True)
class Meta:
ordering = ('-id',)
def __str__(self):
return self.name+' '+self.last_name
def active_profiles():
return Profile.objects.filter(active=True)
api/views.py
class ContactListView(generics.ListAPIView):
queryset = Profile.objects.all()
serializer_class = UserContactListSerializer
filter_backends = (filters.SearchFilter,)
search_fields = ('name', 'last_name',)
def get(self, request, pk, format=None):
contacts = Profile.objects.get(pk=pk)
serializer = UserContactListSerializer(contacts)
return Response(serializer.data)
api/serializers.py
class UserContactListSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['name','last_name','contacts']
I don't know what exactly is going on in your list_contacts but if you want to use the same serializer as a field in itself, you currently can't.
While Django models allow you to use 'self' as the reference, DRF doesn't.
What you can instead do is create another serializer and use that as the field.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ("id", "first_name", "last_name")
class UserContactListSerializer(serializers.ModelSerializer):
contacts = UserSerializer(many=True)
class Meta:
model = Profile
fields = ("id", "first_name", "last_name", "contacts")