Trying to pass a nested foreignkey object to a another model

I’ve been stumped for days; hoping one of you wizards can get me out of this pickle…

I have a model called ExtraSlot

class ExtraSlot(models.Model):
        .......
	employee = models.ForeignKey(Employee, on_delete = models.CASCADE, related_name="employee")

this is the serializer

class ExtraSlotSerializer(serializers.ModelSerializer):
         
        employee = EmployeeSerializer(many=True) <-- If I add this it tries to iterate through and errors 
             out

	class Meta:
		model = ExtraSlot
		fields = (..... 'employee')
                fields = ('__all__') <- also used this to no avail
		depth = 3

I’m trying to add an Employee to the model; in the admin panel it is fine. The employee object can be selected. The DRF api doesn’t show anything; I’ve read HTML list input isn’t supported which is fine but the employee field as an input (even in raw format) doesn’t show at all.

Employee extends User (AbstractBaseUser) - here is the list error if I try many=true and passing the entire serializer.

Hope I’m clear enough - I just want to be able to pass an Employee to the other model/create the relationship =’( it’s been so long by brain is fried!

TypeError: ‘Employee’ object is not iterable (if I try pass EmployeeSerializer with many true; which makes sense.

employee = EmployeeSerialzer() - passes the entire object as if I want to create a new one?!

Please help :frowning:

I’m a bit confused here.

Your ExtraSlotSerializer is defined as a ModelSerializer for WorkingSlot, but you’ve shown us the definition for an ExtraSlot.

What model are you trying to serialize?

1 Like

Sorry Ken you’re right I was trying to give you a simplified version. ExtraSlot and WorkingSlot are the same model. I’ll edit the question.

I’m trying to serialise ExtraSlot model which has a ForeinKey.

In this case, many would not be true. You have the foreign key in ExtraSlot, which means it contains a reference to one employee.

Also, if you take out that line, do you get the ForeignKey in your serialized model? If so, what does your EmployeeSerializer look like? Have you verified that it is working correctly?

1 Like

I thought so but stupidity made me try many=true. Yes reference only one employee.

If I remove that line before the meta class I can add (via drop down list) the employee in the admin view/GUI and it saves it to the model; I can then call and do what ever I need to BUT it doesn’t show up at all on the DRF API view.

So to make sure I’ve got this right -

  • You’ve got 'employee' in your fields in your Meta class for ExtraSlotSerializer
  • But, doing a GET on /extraslot/1/ (or whatever the appropriate url would be) does not show a field named employee?
1 Like
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' )
        extra_kwargs = {}

    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 Employee searilizer (it’s from another app but I’ve imported it correctly (according to docs this is fine to do). The Employee serializer works fine I’m just passing mostly strings to validate and create the user+employee.

Yes absolutely.

class ExtraSlotSerializer(serializers.ModelSerializer):

	class Meta:
		model = ExtraSlot
		fields = ('starttime', 'finishtime', 'postcode', 'minislots', 'employee')
		depth = 3

With this here:

sorry I know I should post pics but quickest/best way to show you.

Again, I’m getting confused here. That screenshot doesn’t answer my question. If you do a GET on an ExtraSlot, do you see a field for employee in the JSON response?

1 Like

Sorry I’m just excited to try and solve this - GET on ExtraSlot does a return a field for employee in JSON response. I have to entries to that model which I entered through the Admin page.

Ok, now if you add that line:

back into your ExtraSlotSerializer, are you saying that the employee field no longer shows up?

1 Like
employee = EmployeeSerializer()

returns an Employee field in the JSON. Plus this …

without passing the EmployeeSerializer it still returns an Employee field in the json but no field to post or assign it.

Sorry I feel like an idiot here. Sorry for any annoyance and confusion.

BOTH return Employee field in the json response on GET. The POST options is the difference. Without passing the EmployeeSerializer there’s no way to assign the model.

Ah, ok. So we’re not talking about serialization here, we’re talking about deserialization.

So lets go back to the root question.

What exactly are you trying to do that isn’t working?

1 Like

OK. Sorry I’ll read the docs on deserialization.

I’m trying to assign the Employee model to the ExtraSlot model using the API call.

In the simple case, you could pass the ID field of the target Employee model to the employee field of the ExtraSlot model.
Somehow, the client (JavaScript, calling service, whatever) needs to identify which Employee is to be assigned. It might as well pass the ID back as anything else.

1 Like

Yes this is exactly what I’m looking to implement from the front-end. But how and where on the POST request am I meant to put that employee id; if there isn’t a field for me to do so?!
I will send the Employee ID to the front end else where and they can use that ID to post to the ExtraSlot model which will assign the ForeignKey.

Do I not need a serialized field to pass that id to the ExtraSlot model?!

Look at the JSON response you receive on a GET for a specific ExtraSlot - you have the field named employee in that structure. If you POST that same structure with an employee field, you have assigned the user.

1 Like

I have a nested field for Employee.

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

The primary key is the user.email - Do I pass this only? or every employee field.

Ok, to clarify -

when you don’t have the nested serializer.

1 Like

OK If I try to save an ExtraSlot instance from the admin page of the model without the Employee field - it won’t let me save it (required). If I delete the entries from ExtraSlot and do a GET request on ExtraSlot it comes back empty. I don’t know understand what you want me to replicate.

Shall I make the employee field null = True, blank = True and then GET one of those entries?