Reputation: 747
What i am doing is django 2 project call api to django 1 project to book an appointment in Appointment
table and save the details into BookAppt
table.
I am trying to save the data from api call to an api using view. Everything else works but however, the foreign key to user model userId
give me this error : ValueError: Cannot assign "4": "BookAppt.patientId" must be a "MyUser" instance.
I don't know what is the problem as i did say same post with the same value to that BookAppt table API and it works normally. But when saving using the API call, it gave me this error.
Updated error
After updating my code based on the answer given, i got this error now. {"patientId":["This field is required."]}
Still have no idea why even though i specify it already.
Please help as i have been stuck at this part for 2 days now.
Here is my code:
Updated code, do note that it is django 2 calling to django 1
model.py
django 1
class Appointments (models.Model):
patientId = models.IntegerField()
clinicId = models.CharField(max_length=10)
date = models.DateField()
time = models.TimeField()
created = models.DateTimeField(auto_now_add=True)
ticketNo = models.IntegerField()
STATUS_CHOICES = (
("Booked", "Booked"),
("Done", "Done"),
("Cancelled", "Cancelled"),
)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="Booked")
django 2
class MyUser(AbstractUser):
userId = models.AutoField(primary_key=True)
gender = models.CharField(max_length=6, blank=True, null=True)
nric = models.CharField(max_length=9, blank=True, null=True)
birthday = models.DateField(blank=True, null=True)
birthTime = models.TimeField(blank=True, null=True)
class BookAppt(models.Model):
clinicId = models.CharField(max_length=20)
patientId = models.ForeignKey(MyUser, on_delete=models.CASCADE)
scheduleTime = models.DateTimeField()
ticketNo = models.CharField(max_length=5)
status = models.CharField(max_length=20)
serializer
django 1
class AppointmentsSerializer(serializers.ModelSerializer):
class Meta:
model = Appointments
fields = ('id', 'patientId', 'clinicId', 'date', 'time', 'created', 'ticketNo', 'status')
django 2
class MyUserSerializer(serializers.ModelSerializer):
class Meta:
model = MyUser
fields = ('userId', 'username', 'email', 'first_name', 'last_name', 'gender', 'nric', 'birthday', 'birthTime')
read_only_fields = ('userId',)
class BookApptSerializer(serializers.ModelSerializer):
patientId = MyUserSerializer(many=False)
class Meta:
model = BookAppt
fields = ('id', 'patientId', 'clinicId', 'scheduleTime', 'ticketNo', 'status')
view.py
django 1
class AppointmentsViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = Appointments.objects.all()
serializer_class = AppointmentsSerializer
django 2
@csrf_exempt
def my_django_view(request):
if request.method == 'POST':
r = requests.post('http://127.0.0.1:8000/api/makeapp/', data=request.POST)
else:
r = requests.get('http://127.0.0.1:8000/api/makeapp/', data=request.GET)
if r.status_code == 201 and request.method == 'POST':
data = r.json()
patient = request.data['patientId']
patientId = MyUser.objects.get(id=patient)
saveget_attrs = {
"patientId": patientId,
"clinicId": data["clinicId"],
"scheduleTime": data["created"],
"ticketNo": data["ticketNo"],
"status": data["status"],
}
saving = BookAppt.objects.create(**saveget_attrs)
return HttpResponse(r.text)
elif r.status_code == 200: # GET response
return HttpResponse(r.json())
else:
return HttpResponse(r.text)
class BookApptViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = BookAppt.objects.all()
serializer_class = BookApptSerializer
Upvotes: 1
Views: 463
Reputation: 3506
Your Appointments model - you work with MyUser model rather than its id,
so it makes sense to give names of your foreign key-referenced models as patient
rather than patient_id
, so
class Appointments (models.Model):
patient = models.ForeignKey(MyUser, on_delete=models.CASCADE)
clinicId = models.CharField(max_length=10)
date = models.DateField()
time = models.TimeField()
created = models.DateTimeField(auto_now_add=True)
ticketNo = models.IntegerField()
STATUS_CHOICES = (
("Booked", "Booked"),
("Done", "Done"),
("Cancelled", "Cancelled"),
)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="Booked")
Than, in your serializers.py:
class MyUserSerializer(serializer.ModelSerializer):
# Whatever you like to serialize
class Meta:
model = MyUser
Then, the Appintment serializer needs to be adjusted as well:
class AppointmentsSerializer(serializers.ModelSerializer):
# Notice this - the patient is serailized using MyUserSerializer
patient = MyUserSerializer(many=False, read_only=False)
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
time = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats)
created = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
class Meta:
model = Appointments
# Now, you work with patient object, not with patientId
# clinicId can still be an Id as long as it's not a foreign key
fields = ('id', 'patient', 'clinicId', 'date', 'time', 'created', 'ticketNo', 'status')
class BookApptSerializer(serializers.ModelSerializer):
# Same here - the patient is serailized using MyUserSerializer
patient = MyUserSerializer(many=False, read_only=False)
valid_time_formats = ['%Y-%m-%d %H:%M', '%Y-%m-%d %I:%M%p', '%Y-%m-%d %I:%M %p']
scheduleTime = serializers.DateTimeField(format="%Y-%m-%d %I:%M %p", input_formats=valid_time_formats)
class Meta:
model = BookAppt
fields = ('id', 'patient', 'clinicId', 'scheduleTime', 'ticketNo', 'status')
Now, in your view you'll have to explicitly read the patient:
patient = MyUser.objects.get(id=patientId)
provided pateintId is an integer value of the id you're sure it exists, and then
saveget_attrs = {
# This has to be object, not the id, that's why it was breaking
"patient": patient,
"clinicId": data["clinicId"],
"scheduleTime": data["created"],
"ticketNo": data["ticketNo"],
"status": data["status"],
}
savingIntoBookApptTable = BookAppt.objects.create(**saveget_attrs)
return HttpResponse(r.text)
Regarding the datetime field you can use in your Appointments
model:
time_scheduled = models.DateTimeField(default=datetime.now, blank=True)
Just as your created = models.DateTimeField(auto_now_add=True)
does.
You can replace default
with something like
default=lambda self.date, self.time: scheduled(self.date, self.time)
So it will be like:
time_scheduled = models.DateTimeField(default=lambda self.date, self.time: scheduled(self.date, self.time), blank=True)
where scheduled
calculates and formats your datetime out of date and time provided - your helper function.
This will assign time automatically at the time of object creation, but you can
specify it later, if you wish. With the field like this you can exclude one of the fields representing date and time.
A sample view format - just to demonstrate how to read user:
from rest_framework.renderers import JSONRenderer
from rest_framework.permissions import AllowAny
from rest_framework.decorators import api_view, renderer_classes, permission_classes
# If you need GET as well, this would be @api_view(['POST', 'GET'])
@api_view(['POST'])
@renderer_classes((JSONRenderer,))
@permission_classes([AllowAny,])
def read_user_view(request):
try:
user_id = request.data['user_id']
user = User.objects.get(id=int(user_id))
except ObjectDoesNotExist as e:
user = User.objects.create(id=user_id)
# Any other processing if user created
serializer = MyUserSerializer(user, many=False)
return Response(serializer.data)
Upvotes: 1