I have one user model and Accesskey model. I want to save user who is accessing the API(access_key) in the accesskey table.
models.py
class AccessKeys(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='user',null=True)
access_keys =models.CharField(max_length=400)
def __str__(self):
return self.access_keys
serializers.py
class AccessKeySerializer(serializers.ModelSerializer):
user_id = serializers.RelatedField(source='CustomUser', read_only=True)
access_keys = serializers.CharField(max_length=200,required=True)
class Meta:
model =AccessKeys
fields = '__all__'
views.py
class AccessKeyView(generics.ListCreateAPIView):
permission_classes = [IsAuthenticated, ]
queryset = AccessKeys.objects.all()
serializer_class = AccessKeySerializer
def post(self,request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=HTTP_201_CREATED)
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
when I'm saving accesskey in the model there is null value in user_id field.
Related
currently when i send a get request i get what i want. But when i do a Post it throws an error saying {"user": ["This field is required."]} even though i put 'user' in read_only_fields.
heres the code:
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username', 'email']
class SaleHistorySerializier(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = SaleHistory
fields =['id', 'user', 'product', 'date_bought']
read_only_fields = ('user',)
depth = 1
models.py
class SaleHistory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owner')
product = models.ForeignKey(SaleItems, on_delete=models.RESTRICT, default=None)
date_bought = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f' {self.product}, {self.user}, {self.id}'
api.py create part
class SaleHistoryVS(viewsets.ViewSet):
permission_classes = [permissions.IsAuthenticated]
def create(self, request):
serializer = SaleHistorySerializier(data=request.data, many=True)
if serializer.is_valid():
serializer.save(user = request.user)
return Response(serializer.data, status= status.HTTP_201_CREATED)
return Response(serializer.errors, status= status.HTTP_400_BAD_REQUEST)
how do i make it so that i get to create post request without having to user in my post data.
Replace user = UserSerializer() with user = UserSerializer(read_only=True)
I just started using the Django Rest Framework recently and was wondering how to use 2 models within a single serializer. I have a custom model named 'Profile' and am also using a default Django model 'User'. With these two tables, I planned to use nested representations. Finally, in order to test the RegisterAPI, I wanted to create data using the POSTMAN tool but currently, it's not working as expected.
This is what I had done so far:
models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
company = models.CharField(max_length=100, blank=True, null=True)
address = models.TextField()
views.py:
class RegisterAPI(APIView):
permission_classes = [AllowAny]
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
content = {
'result': 'Thanks for registering!'
}
return Response(content, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py:
from rest_framework import serializers
from myapp.models import Profile
from django.contrib.auth.models import User
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['company', 'address']
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(many = True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
password = validated_data.pop('password', None)
# instance = self.Meta.model(**validated_data)
user = User.objects.create(**validated_data)
if password is not None:
user.set_password(password)
user.save()
Profile.objects.create(user = user, **profile_data)
return user
Within POSTMAN, I am not able to set the fields 'company' and 'address' for the Profile serializer. How can I do this?
I can't save model with Foreignkey field.
Thanks to "azudo" problem solved. Solution below
For example I have simple models:
class User(AbstractUser):
class Meta:
pass
email_validator = EmailValidator()
username = models.CharField('Name', max_length=150, )
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField('Email', blank=True, unique=True, validators=[email_validator], )
...
class Package(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='packages')
description = models.CharField('Description', max_length=256, default='description')
weight = models.CharField('weight', max_length=256, default='weight')
...
View (the user is guaranteed to be in the request):
#api_view(["POST"])
def test(request):
data = request.data
data['user'] = User.objects.get(id=request.user.id)
serializer = PackageSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
else:
return JsonResponse(serializer.errors)
My serializers:
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = '__all__'
class PackageSerializer(ModelSerializer):
class Meta:
model = Package
fields = (
'user', 'description', 'weight', 'dimensions', 'estimated_shipping_cost', 'deliver_to_date')
def to_representation(self, instance):
self.fields['user'] = UserSerializer(many=False, read_only=True)
self.fields['where_from'] = LocationSerializer(many=False, read_only=True)
self.fields['destination'] = LocationSerializer(many=False, read_only=True)
return super().to_representation(instance)
def create(self, validated_data):
user = User.objects.get(validated_data.pop('user'))
package = Package.objects.create(user=user, **validated_data)
return package
json in request:
{
"description": "Some package",
"weight": "12",
}
So, I'have user in database, and want create package for him. But in overridden create in PackageSerializer, validated_data doesn't have user. Please explain what I'm doing wrong.
Versions of django and drf:
django==2.2.4
djangorestframework==3.10.2
Solution:
Serializer:
class PackageSerializer(ModelSerializer):
user = UserSerializer(many=False, read_only=True)
class Meta:
model = Package
fields = (
'user', 'description', 'weight', 'dimensions', 'estimated_shipping_cost', 'deliver_to_date')
def create(self, validated_data):
user = User.objects.get(validated_data.pop('user'))
package = Package.objects.create(user=user)
return package
View:
#api_view(["POST"])
def create_package(request):
data = request.data
serializer = PackageSerializer(data=data)
if serializer.is_valid():
serializer.save(user=request.user)
return JsonResponse(serializer.data)
else:
return JsonResponse(serializer.errors)
DRF will ignore included fields that are marked as read-only so the caller cannot include read-only data. If you want to include additional attributes simply pass them as keyword args to save:
https://www.django-rest-framework.org/api-guide/serializers/#passing-additional-attributes-to-save
e.g.
#api_view(["POST"])
def test(request):
data = request.data
serializer = PackageSerializer(data=data)
if serializer.is_valid():
serializer.save(user=request.user)
return JsonResponse(serializer.data)
else:
return JsonResponse(serializer.errors)
I have A models.py as this
models.py
class User(AbstractUser, BaseModel):
full_name = models.CharField(max_length=64)
addresss=models.CharField(max_length=40)
phoneno=models.IntegerField(null=True, blank=True)
email=models.EmailField()
password=models.CharField(max_length=40)
re_password=models.CharField(max_length=40)
gender=models.IntegerField(choices=gender_choice,default='0')
serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('full_name','id','addresss','phoneno','email','gender')
views.py
class StudentViewset(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
http_methods = ['get', 'post','put','delete']
def create(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
row = serializer.data
user=User.objects.get_or_create(
defaults={'full_name':row['user']['full_name'],'addresss':row['addresss'],
'phoneno':row['phoneno'],'password':row['password'] ,'re_password':row[['re_password'],
'gender':row['gender'] ,'username':username})
My Question:
After Registering Student, I want to generate an email like his/her(address#gmail.com).
How can i do This ?
I am basically a new entrant into Rest framework and relatively new to Django. I am working on an Employee Rest API and I created Employee - Department tables using below Django models. I assigned a foreign key relationship between Employee's-department ID and Department-department ID. Now I want to update the Employee table using PUT operation. But when i update Employee.dept_id, it is not updated with the new value. I understand that since its a read only field, am not able to update it. How to change it to write field? so that i can update the department id in the employee table.
models.py
class Department(models.Model):
dept_id = models.IntegerField(primary_key=True)
dept_name = models.CharField(max_length=30)
def __str__(self):
return self.dept_id
class Meta:
ordering = ('dept_id',)
class Employee(models.Model):
first_name = models.CharField(max_length=30,blank=True)
last_name = models.CharField(max_length=30,null=True,blank=True)
emp_id = models.AutoField(primary_key=True)
hire_date = models.DateField(default=datetime.date.today)
email_id = models.EmailField(blank=True)
dept = models.ForeignKey(Department, null=True,blank=True,related_name="dept")
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
class Meta:
ordering = ('emp_id',)
My serializers for the above models are
serializers.py
class DepartmentSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Department
fields = ('dept_id','dept_name')
class EmployeeSerializer(serializers.ModelSerializer):
dept_id = DepartmentSerializer().get_fields()
class Meta:
model = Employee
fields = ('emp_id','last_name','first_name','hire_date','email_id', 'dept_id')
views.py
#api_view(['GET','POST'])
def employee_list(request, format=None):
"""
List all employees, or create a new employee
"""
if request.method == 'GET':
employees = Employee.objects.all()
serializer = EmployeeSerializer(employees,many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = EmployeeSerializer(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)
#api_view(['GET','PUT','DELETE'])
def employee_detail(request, pk, format=None):
"""
Retrieve, update or delete a employee.
"""
try:
employee = Employee.objects.get(pk=pk)
except Employee.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method=='GET':
serializer = EmployeeSerializer(employee)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = EmployeeSerializer(employee,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method=='DELETE':
employee.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
You need to overwrite the create() and update() views in your Employee Serializer. Please refer this link for complete doc.