Django api调用视图无法保存外键userId

时间:2018-01-29 01:40:02

标签: python django django-rest-framework

我正在做的是django 2项目调用api到django 1项目预约Appointment表中的约会并将详细信息保存到BookAppt表中。

我正在尝试使用视图将数据从api调用保存到api。其他一切都有效但是,用户模型userId的外键给我这个错误:ValueError: Cannot assign "4": "BookAppt.patientId" must be a "MyUser" instance.

我不知道是什么问题,因为我说过与BookAppt表API具有相同值的相同帖子并且它正常工作。但是当使用API​​调用保存时,它给了我这个错误。

更新错误

根据给出的答案更新我的代码后,我现在收到此错误。 {"patientId":["This field is required."]}即使我已经指定它,仍然不知道为什么。

请帮助,因为我已经被困在这个部分2天了。

这是我的代码:

更新了代码,请注意django 2呼叫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)

串行

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

1 个答案:

答案 0 :(得分:1)

您的约会模型 - 您使用MyUser模型而不是其ID, 因此,将外键引用模型的名称设为patient而不是patient_id是有意义的,所以

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")

比你的serializers.py:

class MyUserSerializer(serializer.ModelSerializer):
    # Whatever you like to serialize
    class Meta:
        model = MyUser

然后,还需要调整Appintment序列化器:

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')

现在,在您看来,您必须明确阅读患者:

patient = MyUser.objects.get(id=patientId) 

如果pateintId是你确定它存在的id的整数值, 然后

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)

关于您可以在Appointments模型中使用的日期时间字段:

time_scheduled = models.DateTimeField(default=datetime.now, blank=True)

就像你的created = models.DateTimeField(auto_now_add=True)一样。 您可以使用

之类的内容替换default
default=lambda self.date, self.time: scheduled(self.date, self.time)

所以它会像:

time_scheduled = models.DateTimeField(default=lambda self.date, self.time: scheduled(self.date, self.time), blank=True)

其中scheduled计算并格式化您提供的日期时间和时间 - 您的帮助程序功能。 这将在创建对象时自动分配时间,但您可以 如果您愿意,请稍后再说明。使用这样的字段,您可以排除其中一个表示日期和时间的字段。

示例视图格式 - 仅用于演示如何阅读用户:

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)