Now this is my plan:
I want to be able to show followers for users,but i have a problem.I have to use nested serializers to show serializers which gives me this error:
followers_set= UserSerializer(source='followers',many=True)
NameError: name 'UserSerializer' is not defined
Now i am using this kind of modelling in my API:
Models.py
class User(AbstractUser,PermissionsMixin):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.CharField(max_length=255,unique=True)
username =models.CharField(max_length=80,unique=True,default='SOME STRING')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
class FollowUserModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
author = models.ForeignKey(User,on_delete=models.CASCADE, related_name='followers')
profile = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
created = models.DateTimeField(auto_now=True)
And here are my serializers:
Serializers.py
class UserSerializer(serializers.ModelSerializer):
followers_set= UserSerializer(source='followers',many=True)
class Meta:
model = User
fields = ('id','email','username','followers_set')
How can i modify it in a way that it shows serializers inside serializer??
Use serializers.SerializerMethodField(...) as
class UserSerializer(serializers.ModelSerializer):
followers_set = serializers.SerializerMethodField()
def get_followers_set(self, user):
return UserSerializer(user.followers.all(), source='followers', many=True).data
class Meta:
model = User
fields = ('id', 'email', 'username', 'followers_set')
Related
sorry my english is not good.
Get request book_id(pk)
How do I serialize ManyToOne fields using BookSerializer to retrieve something
class Book(TimeStampedModel):
name = models.CharField(max_length=25, null=False)
owner = models.ForeignKey(User, on_delete=models.DO_NOTHING,unique=True)
...
class Meta:
db_table = 'books'
class BookMember(TimeStampedModel):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=False)
book = models.ForeignKey(Book, on_delete=models.CASCADE, null=False)
class Meta:
db_table = 'book_member'
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=20, unique=True)
email = models.EmailField(verbose_name=_('email'))
...
class Meta:
db_table = 'user'
class BookSerializer(serializers.ModelSerializer):
user = UserDetailSerializer(read_only=True, many=True, required=False)
owner = UserDetailSerializer(read_only=True, many=True, required=False)
class Meta:
model = Book
fields = '__all__'
I need to book retrieve
class BookViewSet(ModelViewSet):
permission_classes = [AllowAny]
queryset = Book.objects.all()
serializer_class = BookSerializer
renderer_classes = [JSONRenderer]
def retrieve(self, request, *args, **kwargs):
instance = get_object_or_404(self.queryset, many=True)
serializer = self.get_serializer(instance)
return serializer.data
You can span a ManyToManyField [Django-doc] over you BookMember model:
from django.conf import settings
class Book(TimeStampedModel):
# …
owner = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING
)
members = models.ManyToManyField(
settings.AUTH_USER_MODEL,
through='BookMember'
)
# …
class Meta:
db_table = 'books'
class BookMember(TimeStampedModel):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING
)
book = models.ForeignKey(
Book,
on_delete=models.CASCADE
)
class Meta:
db_table = 'book_member'
Then you can serialize with:
class BookSerializer(serializers.ModelSerializer):
user = UserDetailSerializer(read_only=True, many=True, required=False)
members = UserDetailSerializer(read_only=True, many=True, required=False)
class Meta:
model = Book
fields = '__all__'
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: Usually it is better to work with a OneToOneField [Django-doc]
instead of a ForeignKey that has unique=True. A OneToOneField is a ForeignKey with unique=True and some small
modifications: for example it uses by default the name of the model in lowercase as
related_name=… [Django-doc]
and makes accessing the relation in reverse more convenient since that does not require a manager in between.
Note: Specifying null=False [Django-doc] is not necessary: fields are by default not NULLable.
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 ?
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)
I am trying to attribute Likes to the articles but i don't know why i am getting this error.
Models.py
class User(AbstractUser,PermissionsMixin):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.CharField(max_length=255,unique=True)
username =models.CharField(max_length=80,unique=True,default='SOME STRING')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
class LikeUserModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
author = models.ForeignKey(User, on_delete=models.CASCADE,related_name='userlikes')
profile = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
created = models.DateTimeField(auto_now=True)
Serializers.py
class UserViewSerializer(serializers.HyperlinkedModelSerializer):
userlikes = UserSerializer(many=True)
class Meta:
model = User
fields = ('id','email','username','userlikes',)
I defined everything right,no typo or so.
email is not a field in your UserViewSerializer. Only userlikes is. You can either write fields like this:
fields = ('userlikes',)
or define your fields within the UserSerializer if you don't want all the User model fields.
I am trying to serialize three django models in a section of my api, but it seems he doesn't like the way I do it .. Im following the documentation of https://www.django-rest-framework.org/api-guide/relations/#nested-relationships
I have tried to create 3 serializers one for each model and then put everything together in the fields of the last
serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['name', 'user']
class UserCompanySerializer(serializers.ModelSerializer):
class Meta:
model = UserCompany
fields = ['name']
class UserInfoSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer
companys = UserCompanySerializer(many=True)
class Meta:
model = CustomUser
fields = ['email', 'profile', 'companys']
I thought it would work but it returns the error:
ImproperlyConfigured at /user_info
Field name profile is not valid for model CustomUser.
models.py
class UserCompany(models.Model):
name = models.CharField(max_length=150, unique=True)
def __str__(self):
return self.name
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
is_active = models.BooleanField(default=False)
companys = models.ForeignKey(UserCompany, on_delete=models.CASCADE, null=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
class UserProfile(models.Model):
name = models.CharField(max_length=300, unique=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return self.name