Build User API

I am trying to build an api for my NewUser Model, but i keep getting null value in column “city_id” of relation “users_newuser” violates not-null constraint, i am sending this value “city” in the post request so why does it return null.

Views.py

class UserViewSet(viewsets.ViewSet):
    def list(self, request): #/api/users (get)
        users= NewUser.objects.all()
        serializer = UserSerialiser(users, many=True)
        return Response(serializer.data)

    def create(self, request): #/api/users (post)
        serializer = UserSerialiser(data=request.data)
        if serializer.is_valid():
            serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    
    def retrieve(self, request, pk=None): #/api/users/<str:id> (get)
        user = NewUser.objects.get(id=pk)
        serializer = UserSerialiser(user)
        return Response(serializer.data)

    def update(self, request, pk=None): #/api/users/<str:id> (put)
        user = NewUser.objects.get(id=pk)
        serializer = UserSerialiser(instance=user, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
    
    def destroy(self, request, pk=None): #/api/users/<str:id> (put)
        user = NewUser.objects.get(id=pk)
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

serializer.py

class UserSerialiser(serializers.ModelSerializer):
    class Meta:
        model = NewUser
        fields = '__all__'
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = NewUser(
            username=validated_data['username'],
            email=validated_data['email']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

models.py

class CitiesCity(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=200)
    slug = models.CharField(max_length=255, blank=True, null=True)
    name_std = models.CharField(max_length=200)
    population = models.IntegerField()
    elevation = models.IntegerField(blank=True, null=True)
    kind = models.CharField(max_length=10)
    timezone = models.CharField(max_length=40)
    country = models.ForeignKey('CitiesCountry', models.DO_NOTHING)
    region = models.ForeignKey('CitiesRegion', models.DO_NOTHING, blank=True, null=True)
    subregion = models.ForeignKey('CitiesSubregion', models.DO_NOTHING, blank=True, null=True)

class CitiesCountry(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=200)
    slug = models.CharField(max_length=255, blank=True, null=True)
    code = models.CharField(unique=True, max_length=2)
    code3 = models.CharField(unique=True, max_length=3)
    population = models.IntegerField()
    area = models.IntegerField(blank=True, null=True)
    currency = models.CharField(max_length=3, blank=True, null=True)
    currency_name = models.CharField(max_length=50, blank=True, null=True)
    language_codes = models.CharField(max_length=250, blank=True, null=True)
    phone = models.CharField(max_length=20)
    tld = models.CharField(max_length=5)
    capital = models.CharField(max_length=100)
    continent = models.ForeignKey(CitiesContinent, models.DO_NOTHING, blank=True, null=True)
    currency_symbol = models.CharField(max_length=31, blank=True, null=True)
    postal_code_format = models.CharField(max_length=127)
    postal_code_regex = models.CharField(max_length=255)

    def __str__(self):
        return self.name

    class Meta:
        managed = False
        db_table = 'cities_country'
        ordering = ('name',)

category_choices = (
    ('Movies','Movies'),
    ('Tv Shows','Tv Shows'),
    ('Comedy','Comedy'),
    ('Music','Music'),
    ('Documentaries','Documentaries'),
    ('Tutorials','Tutorials'),
    ('Food','Food'),
    ('Animals','Animals'),
    ('Crafts','Crafts'),
    ('News','News'),
    ('Travel','Travel'),
    ('Technology','Technology'),
    ('Education','Education'),
    ('Fashion','Fashion'),
    ('Gaming','Gaming'),
    ('Health','Health'),
    ('Sports','Sports'),
    ('Vehicles','Vehicles'),
    ('Nature','Nature'),
    ('Hiking','Hiking'),
    )

class NewUser(AbstractUser):
    class Role(models.TextChoices):
        ADMIN = "Admin", 'Admin'
        WATCHER = "Watcher", 'Watcher'
        CONTENT_CREATOR = "Content Creator", 'Content Creator'
        SELLER = "Seller", 'Seller'
        ADVERTISER = "Adevertiser", 'Adevertiser'
        PROMOTER = "Promoter", 'Promoter'
    base_role = Role.WATCHER
    role = models.CharField(max_length=50, choices=Role.choices, default=Role.WATCHER)
    uuid = models.UUIDField(primary_key=True,default=uuid.uuid4, editable=False, max_length=36)
    mobile = PhoneNumberField(null=False, blank=False, unique=True)
    first_name = models.CharField(_("first name"), max_length=150)
    last_name = models.CharField(_("last name"), max_length=150)
    email = models.CharField(unique=True ,max_length=254)
    profile_img = models.ImageField(null=True, blank=True, upload_to='images/profiles/', default='images/profiles/user_new.png')
    street= models.CharField(max_length=200, null=True, blank=True)
    Building= models.CharField(max_length=200, null=True, blank=True)
    Floor= models.IntegerField(null=True, blank=True)
    Flat= models.IntegerField(null=True, blank=True)
    Landmark= models.TextField(null=True, blank=True)
    country = models.ForeignKey(CitiesCountry, on_delete=models.CASCADE)
    city = models.ForeignKey(CitiesCity, on_delete=models.CASCADE)
    categories = MultiSelectField(choices=category_choices, max_choices=4, max_length=100)
    terms = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add= True)

    def __str__(self):
        return self.username

urls.py

path('users/api/', views.UserViewSet.as_view({
        'get': 'list',
        'post': 'create',
    })),
    path('users/api/<str:pk>', views.UserViewSet.as_view({
        'get': 'retrieve',
        'put': 'update',
        'delete': 'destroy',
    })),


In the create method of the serializer, you are only passing in the username and email to the model and ignoring any other data in validated_data that may be present.

I would also recommend against using __all__ as your fields specification as this risks, in future, you exposing a field on your API that ought to be private.

i updated my serializer to this

class UserSerialiser(serializers.ModelSerializer):
    class Meta:
        model = NewUser
        fields = ['username', 'password', 'email', 'first_name', 'last_name', 'mobile', 'categories', 'country', 'city', 'terms']
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = NewUser(
            username=validated_data['username'],
            email=validated_data['email'],
            first_name =validated_data['first_name'],
            last_name = validated_data['last_name'],
            mobile = validated_data['mobile'],
            categories = validated_data['categories'],
            country = validated_data['country'],
            city = validated_data['city'],
            terms = validated_data['terms'],
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

but now its expecting True or False value for the city but the country is the same and its working !!

I managed to get it to work i was using the city on another function which caused this error.