I have two models Role and User. User model has a foreign-key field associated with model Role.
Model Role
class Role(models.Model):
role_name = models.CharField(max_length=255, blank=False, unique=True)
def __str__(self):
return 'Role Object ({})'.format(self.id, self.role_name)
Model User
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(max_length=255, blank=False)
last_name = models.CharField(max_length=255, blank=False)
email = models.EmailField(max_length=255, blank=False, unique= True)
phone_number = models.BigIntegerField(blank=False, unique= True)
password = models.TextField(blank=False)
company_name = models.CharField(max_length=255, null=True, unique=True)
is_active = models.BooleanField(default= False)
role = models.ForeignKey(Role, related_name='group_name', on_delete=models.CASCADE, blank=False)
business = models.ForeignKey(Businesses, on_delete=models.CASCADE, null=True)
objects = UserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return 'User Object ({})'.format(self.id)
Using ModelSerializer and ListAPIView I want to get the list of all the users as shown below -
{
"first_name": "",
"last_name":"",
"email":"",
"phone_number":,
"is_active":"",
"role":{
"id":1,
"role_name": "Admin"
}
}
Also, I have created serializers -
class AdminSerializer(serializers.ModelSerializer):
role = RoleSerializer(read_only=True)
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'email', 'phone_number', 'password', 'role', 'is_active' ]
read_only_field = ['role_name']
extra_kwargs = {
'password':{
'write_only':True
},
'is_active':{
'required':False
}
}
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = Role
field = ['id', 'role_name']
What exactly should I do to my serializer to achieve desire output. What exactly should I write in my ListAPIView() what a ListAPIVIew returns.
class UsersListAPIView(ListAPIView):
queryset = User.objects.all()
serializer_class = AdminSerializer
def list(self, request):
queryset = self.get_queryset().filter(role=request.query_params.get['id']).prefetch_related("group_name")
serializer = AdminSerializer(queryset, many=True)
return Response(serializer.data)
This returns an error -
TypeError: 'method' object is not subscriptable
Related
I have multiple users and I designed two models for two users and the rest is super user.
And I have the model User that holds common data for all users.
I want to save the patient post request to two different models: User and Patient; I tried these codes but, didn't work.
This is my Signup view
class PatientSignupView(generics.GenericAPIView):
serializer_class=PatientSignupSerializer
permission_classes = [
permissions.AllowAny
]
def post(self, request, *args, **kwargs):
user_serializer=self.get_serializer(data=request.data)
user_serializer.is_valid(raise_exception=True)
user=user_serializer.save()
return Response({
"user":UserSerializer(user, context=self.get_serializer_context()).data,
"patient":PatientSerializer(patient, context=self.get_serializer_context()).data,
"token":Token.objects.get(user=user).key,
"message":"account created successfully",
})
And here is my Signup Serializer class
class PatientSignupSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(style={"input_type":"password"}, write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'is_doctor', 'is_patient', 'password',
'password_confirm']
extra_fields = {
'password': {'write_only': True},
}
def save(self, **kwargs):
user=User(
username=self.validated_data['username'],
email=self.validated_data['email']
)
password=self.validated_data['password']
password_confirm=self.validated_data['password_confirm']
if password !=password_confirm:
raise serializers.ValidationError({"error":"password do not match"})
user.set_password(password)
user.is_patient=True
user.is_doctor=False
user.save()
PatientSerializer.serialized_data(user)
return user
Here is the PatientSerializer and UserSerializer class
from rest_framework import serializers
from .models import Patient, User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username','email','is_doctor','is_patient']
class PatientSerializer(serializers.ModelSerializer):
class Meta:
model = Patient
fields = ['first_name', 'middle_name', 'last_name', 'address', 'phone_number', 'birth_date', 'gender']
def serialized_data(self, user, **kwargs):
patient = Patient.objects.create(
user = user,
first_name=self.validated_data['first_name'],
middle_name = self.validated_data['middle_name'],
last_name = self.validated_data['last_name'],
address = self.validated_data['address'],
phone_number = self.validated_data['phone_number'],
birth_date = self.validated_data['birthh_date'],
gender = self.validated_data['gender']
)
return patient
Thank you!
It is solved like this
The signup view is:
class PatientSignupView(generics.GenericAPIView):
serializer_class=PatientSignupSerializer
def post(self, request, *args, **kwargs):
user_serializer=self.get_serializer(data=request.data)
user_serializer.is_valid(raise_exception=True)
user=user_serializer.save()
return Response({
"user":UserSerializer(user, context=self.get_serializer_context()).data,
"token":Token.objects.get(user=user).key,
"message":"account created successfully",
})
The serializer class will looks like:
class PatientSignupSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(style={"input_type":"password"}, write_only=True)
first_name = serializers.CharField()
middle_name = serializers.CharField()
last_name = serializers.CharField()
address = serializers.CharField()
phone_number= serializers.CharField()
birth_date = serializers.DateTimeField()
gender = serializers.CharField()
class Meta:
model = User
fields = '__all__'
extra_fields = {'password': {'write_only': True},}
def save(self, **kwargs):
user=User(
username=self.validated_data['username'],
email=self.validated_data['email']
)
password=self.validated_data['password']
password_confirm=self.validated_data['password_confirm']
if password !=password_confirm:
raise serializers.ValidationError({"error":"password do not match"})
user.set_password(password)
user.is_patient=True
user.is_doctor=False
user.save()
Patient.objects.create(user=user,
first_name=self.validated_data['first_name'],
middle_name=self.validated_data['middle_name'],
last_name=self.validated_data['last_name'],
address=self.validated_data['address'],
phone_number=self.validated_data['phone_number'],
birth_date=self.validated_data['birth_date'],
gender=self.validated_data['gender'])
return user
In my project I have created a custom User object with a one to one relation to a Profile object in order to isolate authentication fields.
Profile
class Profile(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
image = models.ImageField(default='/user_images/default.png', upload_to='user_images', blank=True, null=True)
def __str__(self):
return self.first_name + " " + self.last_name
User
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
profile = models.OneToOneField(Profile, related_name="user" ,on_delete=models.CASCADE, default=None, blank=True, null=True)
is_visible = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
My problem now is that i want to create the Profile object with the same request of the User object
View
class CustomView(APIView):
permission_classes = (permissions.AllowAny,)
def post(self, request, format='json'):
serializer = CustomSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Serializer
class CustomSerializer(serializers.Serializer):
# User
email = serializers.EmailField(required=True)
password = serializers.CharField(min_length=8, write_only=True)
# Profile
first_name = serializers.CharField(max_length=50)
last_name = serializers.CharField(max_length=50)
image = serializers.ImageField(allow_null=True, max_length=100, required=False)
def create(self, validated_data):
profile = Profile.objects.create(
first_name = validated_data['first_name'],
last_name = validated_data['first_name'],
image = validated_data['image'],
)
user = User.objects.create(
email = validated_data['email'],
profile = profile
)
user.set_password(validated_data['password'])
user.save()
return user
Now in the database everything is created correctly but i receive this error
Got AttributeError when attempting to get a value for field
first_name on serializer CustomSerializer. The serializer field
might be named incorrectly and not match any attribute or key on the
User instance. Original exception text was: 'User' object has no
attribute 'first_name'.
I suppose this means that a serializer can only handle the creation of one model so i'm supposed to handle my case?
Thanks
I assume that your error comes from to_representation() and what you can do is to set write_only=True on first_name, last_name and image fields like this:
first_name = serializers.CharField(max_length=50, write_only=True)
However, a more clean solution would be to use ModelSerialzier for both User and Profile models. If you do so, you'll have something like:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ("id", "first_name", "last_name", "image")
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ("id", "email", "profile", [...])
def create(self, validated_data):
...
* i have * router.register(r'reseller/', views.UserViewSet)
and router.register(r'one/', views.OneLViewSet)
I want to make nested url like 'reseller/ or {pk}/one/
But i'm failed.
I tried adding DynamicRelationField to User Model but not worked.
my user_model
phone = models.CharField(_('phone number'), max_length=30, blank=True)
address = models.CharField(_('reseller address'), max_length=220, blank=True)
OneL model
id = models.AutoField(_('lottery id'), unique=False, primary_key=True, auto_created=True,)
lno = models.CharField(_('1000ks lottery'), max_length=8, unique=True)
name = models.CharField(_('customer name'), max_length=100, )
reseller = models.ForeignKey('lotto_app.User', on_delete=models.CASCADE)
user_serializer
class UserSerializer(serializers.DynamicModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'phone', 'address', )
oneL serializer
class OneLSerializer(serializers.DynamicModelSerializer):
reseller = fields.DynamicField(source='reseller.username', read_only=True)
class Meta:
model = OneL
fields = (
'id', 'lno', 'name', 'reseller', 'phone', 'address', 'nth', 'is_winner', 'prize_details', 'created_at',
'updated_at')
user dynamicviewset
class UserViewSet(DynamicModelViewSet):
permission_classes = (IsAdmin, IsAuthenticated)
model = User
queryset = User.objects.all()
serializer_class = UserSerializer
OneLviewSet
class OneLViewSet(DynamicModelViewSet):
permission_classes = (IsAuthenticated, IsOwner)
model = OneL
queryset = OneL.objects.all()
serializer_class = OneLSerializer
def create(self, request, *args, **kwargs):
serializer = OneLSerializer(data=request.data)
if serializer.is_valid():
serializer.save(reseller=request.user)
return Response(serializer.data)
def list(self, request, *args, **kwargs):
queryset = OneL.objects.filter(reseller=request.user)
serializer = OneLSerializer(queryset, many=True)
return Response(serializer.data)
I want to change this.url
router.register(r'reseller', views.UserViewSet)
router.register(r'one', views.OneLViewSet)
urlpatterns = [
path('api/saledatas/', include(router.urls))
]
TO THIS
router.register(r'reseller', views.UserViewSet)
router.register(r'reseller/{pk}/one', views.OneLViewSet) #or <int:pk>
urlpatterns = [
path('api/saledatas/', include(router.urls))
]
After change
error-- "Request URL: http://localhost:8000/api/saledatas/reseller/1/one/" Not Found!
And How to make http://localhost:8000/api/saledatas/reseller/1/one/ to be work.
create action in Userviewset
#action(detail=True, methods=["get"])
def one(self, request):
''' to get instance just do get_object() it'll give reseller instance '''
user = self.get_object()
ones = user.onel_set.all()
''' now you can work on one '''
I am setting up a Django rest API for accessing my bank account system.
my models serialize well into JSON format except that I dont know how to handle passwords the same way we do with forms. Kindly help. Below are my relevant files.
I have tried defining password fields in serializers.py but when I run the project, it tells me the custom User instance has no attribute 'password1' which I understand is true because AbstractUser has no attributes named password1 and password2.
accounts/models.py:
class User(AbstractUser):
email = models.EmailField(unique=True, blank=True, null=True)
contact_no = models.IntegerField(unique=False, null=True, blank=True)
account_no = models.PositiveIntegerField(
unique=True,
validators=[
MinValueValidator(1000000000),
MaxValueValidator(9999999999)
])
balance = models.DecimalField(
default=0,
max_digits=12,
decimal_places=2
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', ]
def __str__(self):
return str(self.full_name)
#property
def full_name(self):
return '{} {}'.format(self.first_name, self.last_name)
api/serializers.py:
class UserSerializer(RegisterSerializer):
password1 = serializers.CharField(
max_length=100,
style={'input_type': 'password', 'placeholder': 'Password'}
)
password2 = serializers.CharField(
max_length=100,
style={'input_type': 'password', 'placeholder': 'Confirm Password'}
)
class Meta:
model = User
fields = [
'first_name',
'last_name',
'email',
'contact_no',
'password1',
'password2',
]
api/views.py:
from rest_framework import generics
from accounts.models import User
from .serializers import UserSerializer
class UserCreateView(generics.ListCreateAPIView):
serializer_class = UserSerializer
queryset = User.objects.all()
I'm trying to create a new note via a POST request that looks like this: {content: "hello world", user: 1} with a response that looks like this: { id: 1, content: "hello world", user: { id: 1, first_name: "Homer", last_name: "Simpson" }.
After reading at the other foreign key questions I've been able to create the note and get back something like: { id: 1, content: "hello world", user: 1 } but I really need the additional user information.
I attempted to modify the response using the to_representation like so:
class NotePOSTSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
def to_representation(self, instance):
rep = super().to_representation(instance)
"""Convert `status` to human-readable."""
rep['user'] = UserSerializer(id=rep['user'])
return rep
but I got this error: TypeError: Object of type ModelState is not JSON serializable
This is what I've got so far. Thanks in advance!
models.py
class Article(models.Model):
id = models.PositiveSmallIntegerField('Article Id', null=True)
title = models.CharField('Title', max_length=100)
content = models.TextField('Description', blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Note(models.Model):
id = models.PositiveSmallIntegerField('Note Id', null=True)
content = models.TextField('Content', blank=True)
timestamp = models.DateTimeField('Timestamp', auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
class ArticleListView(viewsets.ModelViewSet):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
class NoteListView(viewsets.ModelViewSet):
serializer_class =NoteSerializer
queryset = Note.objects.all()
def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
if self.request.method in ('POST', 'PUT'):
return NotePOSTSerializer
else:
return self.serializer_class
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'first_name', 'last_name', 'email')
class NoteSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
class NotePOSTSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
class ArticleSerializer(serializers.ModelSerializer):
notes = NoteSerializer(many=True, read_only=True)
class Meta:
model = Article
fields = ('id', 'title', 'content', 'created', 'updated', 'notes')
I'm getting completely different errors, so I will just provide working code
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['user'] = UserSerializer(instance=User.objects.get(pk=instance.user_id)).data
# UserSerializer(instance=instance)
return rep