Сбой вложенной модели AbstractUser во время операции обновления с «нулевым значением в столбце« user_id »нарушает ненулевое ограничение» - PullRequest
0 голосов
/ 12 января 2020

Я создаю вложенного абстрактного пользователя «Учитель из пользователя», Мой вариант использования - «Создать пользователя» -> «Затем сделать пользователя учителем»

Я могу создать пользователя и сделать пользователя учителем. , но я не могу обновить поле, В приведенном ниже примере хочу обновить "teacher_cost"

Model.py


from django.contrib.postgres.fields import JSONField
from django.db import models
from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    uid = models.AutoField(verbose_name='ID', 
                                  serialize=False, 
                                  auto_created=True, 
                                  primary_key=True)
    TEACHER = "Teacher"
    STUDENT = "Student"

    user_type = models.CharField(max_length=30, default=STUDENT)
    contact_number = models.CharField(max_length=20, null=True, blank=True)
    address = models.TextField(null=True, blank=True)
    photo = models.ImageField(null=True, blank=True)
    image = models.ImageField(upload_to='users/',
                              default='default/avatar.png')
    approved = models.BooleanField(default=True)

    def save(self, *args, **kwargs):
        if self.user_type == User.TEACHER and self._state.adding:
            self.approved = False
        super().save(*args, **kwargs)

    @property
    def dishes(self):
        ret = self.teacher.dish_set.all()
        if ret:
            return ret
        else:
            return ''


class Teacher(models.Model):
    uid = models.AutoField(verbose_name='ID', 
                                  serialize=False, 
                                  auto_created=True, 
                                  primary_key=True)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(null=True, blank=True)
    teacher_cost = models.DecimalField(
        max_digits=5, decimal_places=2, null=True, blank=True)
    languages = models.CharField(
        max_length=50, null=True, blank=True)
    address = models.TextField(null=True, blank=True)

    def __str__(self):
        return self.user.username

Serializer.py

from rest_framework import serializers, exceptions
from django.contrib.auth.forms import PasswordResetForm
from django.conf import settings
from .models import *
from rest_auth import serializers as rest_auth_serializers
from django.utils.translation import ugettext_lazy as _


class UserDetailsSerializer(serializers.ModelSerializer):
    """
    User model w/o password
    """
    class Meta:
        model = User
        fields = ('pk', 'username', 'email',
                  'first_name', 'last_name', 'contact_number', 'user_type', 'photo', 'address')
        read_only_fields = ('email', )


class UserTeacher(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('teacher',)


class TeacherDetails(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = '__all__'

class TeacherFullDetails(serializers.ModelSerializer):
    user_id = serializers.CharField(source='user.uid')
    username = serializers.CharField(source='user.username')
    first_name = serializers.CharField(source='user.first_name')
    last_name = serializers.CharField(source='user.last_name')
    photo = serializers.ImageField(
        source='user.photo', max_length=None, use_url=True)

    class Meta:
        model = Teacher
        fields = ('user_id', 'username', 'first_name', 'last_name', 'photo', 'teacher_cost')

class TeacherBriefDetails(serializers.ModelSerializer):
    uid = serializers.CharField(source='user.uid')
    first_name = serializers.CharField(source='user.first_name')
    last_name = serializers.CharField(source='user.last_name')

    class Meta:
        model = Teacher
        fields = ('uid', 'first_name', 'last_name',)

class TeacherProfileDetails(serializers.ModelSerializer):
    contact_number = serializers.CharField(source='user.contact_number', required=False)
    first_name = serializers.CharField(source='user.first_name', required=False)
    last_name = serializers.CharField(source='user.last_name', required=False)
    email = serializers.CharField(source='user.email', required=False)
    photo = serializers.ImageField(
        source='user.photo', max_length=None, use_url=True, required=False)
    user = UserDetailsSerializer(read_only=True)
    teacher_cost = serializers.CharField()

    class Meta:
        model = Teacher
        fields = ('user', 'first_name', 'last_name', 'contact_number', 'email', 'photo',
                  'bio', 'teacher_cost')

class TeacherProfileSerializer(serializers.ModelSerializer):
    user = UserDetailsSerializer()
    class Meta:
        model = Teacher
        fields = ("bio", "teacher_cost", "user")

view.py

from rest_framework import generics, viewsets, status, permissions
from .models import *
from .serializers import *
from rest_framework.response import Response
from django.db.models import Q
from .permissions import IsAuthenticatedAndOwner, IsTeacher
from django.shortcuts import get_object_or_404
from django.utils.datastructures import MultiValueDictKeyError
from rest_framework.views import APIView
import json
import logging

class TeacherProfile(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    lookup_field = "username"

    def get_object(self):
        if self.action == "partial_update":
            return get_object_or_404(User, username=self.kwargs['username'])
        return get_object_or_404(Teacher, user__username=self.kwargs['username'])

    def get_serializer_class(self):
        if self.action == "partial_update":
            return UserDetailsSerializer
        else:
            return TeacherProfileDetails

class TeacherListCreateAPIView(APIView):
        logger = logging.getLogger(__name__)

        def get(self, request, *args, **kwargs):
            teacherList = Teacher.objects.filter(user__username=kwargs["username"])
            self.logger.info("Printing teacher list")
            self.logger.info(teacherList)
            serializers = TeacherProfileDetails(teacherList, many=True)
            return Response(serializers.data)
        def post(self, request, *args, **kwargs):
            self.logger.info("-----------------put ------------")
            serializers = TeacherProfileDetails(data=request.data)
            # photo = request.FILES['file']
            if serializers.is_valid():
                serializers.save()
                return Response(serializers.data, status=status.HTTP_201_CREATED)
            return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
       def put(self, request, *args, **kwargs):
            serializers = TeacherProfileDetails(data=request.data, many=True)
            self.logger.info(serializers)
            if serializers.is_valid():
                serializers.save()
                return Response(serializers.data, status=status.HTTP_201_CREATED)
            return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)


# /user/<str:username>/profile
class UserProfile(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    lookup_field = "username"

    def get_object(self):
        return get_object_or_404(User, username=self.kwargs['username'])

    def get_serializer_class(self):
        return UserDetailsSerializer

urls.py

from django.urls import path
from .views import *

urlpatterns = [
    path('teacher/<str:username>/profile',
         TeacherProfile.as_view({'get': 'retrieve', 'delete': 'destroy', 'patch': 'partial_update'})),

   path('teacherlist/<str:username>/',
         TeacherListCreateAPIView.as_view(), name="teacher-list"),

]

Ошибка ниже при вызове команды post для обновления профиля пользователя

post

http://localhost:8002/api/v1/teacherlist/rayees/

Форма json data

{

     "teacher_cost": "25.00"
    }

Ошибка получения ниже

IntegrityError at /api/v1/teacherlist/rayees/
null value in column "user_id" violates not-null constraint
DETAIL:  Failing row contains (2, null, 25.00, null, null, null).


Request Method: POST
Request URL: http://localhost:8002/api/v1/teacherlist/rayees/
Django Version: 2.2.4


1 Ответ

1 голос
/ 12 января 2020

, поскольку в модели Teacher пользователю требуются поля, и вы отправляете запрос на публикацию, он создаст нового учителя с этим пользователем. Если вы хотите создать нового учителя, то вам следует использовать сообщение, для этого вам нужно user

Если вы хотите обновить данные пользователя, вы можете использовать метод исправления, проверьте код метода put

class TeacherListCreateAPIView(APIView):
        logger = logging.getLogger(__name__)

        def get(self, request, *args, **kwargs):
            teacherList = Teacher.objects.filter(user__username=kwargs["username"])
            self.logger.info("Printing teacher list")
            self.logger.info(teacherList)
            serializers = TeacherProfileDetails(teacherList, many=True)
            return Response(serializers.data)
        def post(self, request, *args, **kwargs):
            """ creating new user """
            serializers = TeacherProfileDetails(data=request.data)
            # photo = request.FILES['file']
            if serializers.is_valid():
                serializer.validated_data['user'] = User.objects.filter(username=kwarsg['username'])
                serializers.save()
                return Response(serializers.data, status=status.HTTP_201_CREATED)
            return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)


        def patch(self, request, *args, **kwargs):
            teacher = TeacherProfileDetails.objects.get(user__username=kwargs['username'])
            serializers = TeacherProfileDetails(data=request.data, instance=teacher)
            self.logger.info(serializers)
            if serializers.is_valid():
                serializers.save()
                return Response(serializers.data, status=status.HTTP_201_CREATED)
            return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)


, теперь вы можете сделать запрос на исправление для http://localhost:8002/api/v1/teacherlist/rayees/ с заданными данными обновит запись.

...