【问题标题】:Django api call in view unable to save for foreign key userId视图中的 Django api 调用无法保存外键 userId
【发布时间】:2018-07-07 16:16:27
【问题描述】:

我正在做的是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

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    您的 Appointments 模型 - 您使用 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)
    

    【讨论】:

    • 我有一个问题,patient = MyUserSerializer(many=False, read_only=True) 不会阻止发布患者(id)吗?因为它是只读的
    • 如果您希望能够发布新用户,请将其设置为 False,您是对的。
    • 因为要预约,所以需要在userId(patientId)中发帖。没有真正发布新用户。
    • 对所有这些麻烦感到抱歉。所以我把这行patient = MyUser.objects.get(id=patientId) 放在if request.method == 'POST': 语句之前?我的(id=patientId) 出现未解析引用错误。
    • DRF 应该允许发布,您也可以将 user_id 发布为整数,使用MyUser.objects.get(id=user_id) 读取对象,然后根据需要将其保存在视图中。
    猜你喜欢
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 1970-01-01
    • 2017-11-16
    • 1970-01-01
    • 2011-11-14
    • 2011-02-24
    • 2011-04-26
    相关资源
    最近更新 更多