Trying to pass a nested foreignkey object to a another model

NOT NULL constraint failed: bookings_extraslot.employee_id

If I set the employee field to null and blank then try POST without the employee_id.

I appreciate your time. Thanks for trying.

Avoid the UI - your client isn’t going to be using it.

Do a GET on an ExtraSlot and post the JSON here.

1 Like

GET Request on ExtraSlots using Postman (after creating an entry using admin UI)

[
    {
        "starttime": "2021-09-14T20:09:04",
        "finishtime": "2021-09-14T20:09:07",
        "postcode": "e14",
        "minislots": 0,
        "employee": {
            "user": "employee1@admin.com",
            "first_name": "john",
            "last_name": "doe",
            "mobile_number": "123",
            "photo": "http://127.0.0.1:8000/media/photo",
            "calender_sync_info": "123",
            "business": {
                "user": "business1@admin.com",
                "company_name": "business1",
                "description": "123",
                "address": "123",
                "logo": "http://127.0.0.1:8000/media/logo",
                "insurance": "123",
                "company_registration_number": "12",
                "vat_number": "123",
                "business_privacy_policy": "12",
                "subscription_status": "123",
                "number_of_licenses": "123"
            }
        }
    }
]

If I delete that entry and do a GET request I get an empty JSON response.

If I try forcing the … “employee_id” : “employee1@admin.com
Or … “employee”: { “user” : “employee1@admin.com
Through a post request I get…

NOT NULL constraint failed: bookings_extraslot.employee_id


I have no idea how I can pass the employee_id as a field so the ExtraSlot can save it.

class ExtraSlot(models.Model):
	starttime = models.DateTimeField()
	finishtime = models.DateTimeField()
	postcode = models.CharField(max_length=100)
	minislots = models.IntegerField(default=0)
	employee = models.ForeignKey(Employee, on_delete = models.CASCADE, related_name="employee")
	def get_minislots(self):
		### function to turn time into minislots ###
		
		totaltime = self.finishtime - self.starttime
		return totaltime

	def save(self, *args, **kwargs):
		total = self.get_minislots()
		minutes = total.total_seconds() / 60
		slots = minutes // 5
		self.minislots = slots
		super(ExtraSlot, self).save(*args, **kwargs)
	
		DynamicSlot.objects.create(extraslot=self)

	def __str__(self):

		return str(self.employee) + 's Extra slot date: (' + str(self.starttime.date())+')'

This is the full object maybe super().save is breaking something

Leave the entry for ExtraSlot in the database, but remove the nested serializer.

Do the GET again and post the response.

1 Like

I can’t remove the nested serializer from the entry because it’s required.

The get is simply GET http://127.0.0.1:8000/bookings/extraslot/

which returns .all() the entries.

I’m asking you to post the JSON response of a GET of one ExtraSlot object using the ExtraSlotSerializer without that reference to the nested EmployeeSerializer.

1 Like

Got you afk right now but will do asap!

Also is my employee serializer ok? Maybe that’s the perp.


class EmployeeSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(write_only=True, required=True, validators=[UniqueValidator(queryset=User.objects.all())])

    user_name = serializers.CharField(write_only=True, required=True, validators=[UniqueValidator(queryset=User.objects.all())] )

    password = serializers.CharField(write_only=True, required=True, validators=[validate_password])

    password2 = serializers.CharField(write_only=True, required=True)

    class Meta:
        model = Employee
        fields = ('email', 'user_name', 'password', 'password2' , 'first_name',  'last_name', 'mobile_number', 'photo', 'calender_sync_info', 'business' )

    def validate(self, attrs):
        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError({"password": "Password fields didn't match."})

        return attrs

    def create(self, validated_data):
        password = validated_data.pop('password')
        user = User(email=validated_data['email'], user_name=validated_data['user_name'])
        user.set_password(password)
        user.save()

        Employee.objects.create(user_id= user.email, 
                                first_name=validated_data['first_name'],
                                last_name=validated_data['last_name'],
                                mobile_number=validated_data['mobile_number'],
                                photo='photo',
                                calender_sync_info=validated_data['calender_sync_info'],business=validated_data['business'])
        
        return validated_data

this is the response with employee = EmployeeSerializer()

[
    {
        "starttime": "2021-09-14T21:22:18",
        "finishtime": "2021-09-14T21:22:19",
        "postcode": "e14",
        "minislots": 0,
        "employee": {
            "first_name": "john",
            "last_name": "doe",
            "mobile_number": "123",
            "photo": "http://127.0.0.1:8000/media/photo",
            "calender_sync_info": "123",
            "business": "business1@admin.com"
        }
    }
]

this is the response without

[
    {
        "starttime": "2021-09-14T21:22:18",
        "finishtime": "2021-09-14T21:22:19",
        "postcode": "e14",
        "minislots": 0,
        "employee": {
            "user": "employee1@admin.com",
            "first_name": "john",
            "last_name": "doe",
            "mobile_number": "123",
            "photo": "http://127.0.0.1:8000/media/photo",
            "calender_sync_info": "123",
            "business": {
                "user": "business1@admin.com",
                "company_name": "business1",
                "description": "123",
                "address": "123",
                "logo": "http://127.0.0.1:8000/media/logo",
                "insurance": "123",
                "company_registration_number": "12",
                "vat_number": "123",
                "business_privacy_policy": "12",
                "subscription_status": "123",
                "number_of_licenses": "123"
            }
        }
    }
]

I got it working :sweat_smile: :sweat_smile: :sweat_smile:

I was just debugging and I knew another model with a similar nesting and serialization was working just fine. So I commented out the save function and ran the model and there it was a field for employee on GET and POST successfully.

	def save(self, *args, **kwargs):
		## overring models save function to dynamically fill the mimi-slot

		total = self.get_minislots()
		minutes = total.total_seconds() / 60
		slots = minutes // 5
		self.minislots = slots

		super(ExtraSlot, self).save(*args, **kwargs)
		
		employees_jobtypes = JobTypes.objects.filter(employee__user__user_name=self.employee)

		# super(ExtraSlot, self).save(*args, **kwargs)


		DynamicSlot.objects.create(workingslot=self)

So I now know the culprit is this save function; so I turned it back on (un-commented it) and it’s all working as it should? Like what??? I need to know why… Maybe a bug?! I’m praying it doesn’t break again.