1

I have two models

class Properties(models.Model):
    property_name = models.CharField(max_length=100)
    property_type = models.CharField(choices=TYPE, max_length=50)
    property_location = models.CharField(max_length=100)
    county = models.CharField(choices=COUNTY, max_length=50)
    number_of_units = models.IntegerField()
    date_created = models.DateField(auto_now_add=True)
    last_modified = models.DateField(auto_now=True)
    
    def __str__(self):
        return self.property_name
    
    class Meta:
        verbose_name_plural = "Properties"

class RentalUnits(models.Model):
    unit_number = models.CharField(max_length=10)
    property = models.ForeignKey(Properties, on_delete=models.CASCADE)
    no_of_bedrooms = models.IntegerField(default=0)
    no_of_bathrooms = models.IntegerField(default=0)
    rent_per_month = models.IntegerField(default=0)
    status = models.CharField(max_length=20, choices=STATUS)
    date_created = models.DateField(auto_now_add=True)
    last_modified = models.DateField(auto_now=True)

    def __str__(self):
        return self.unit_number

    class Meta:
        verbose_name_plural = 'Units'

And their corresponding serializers

class PropertiesSerializers(serializers.ModelSerializer):
    class Meta:
        model = Properties
        fields = '__all__'

class RentalUnitsSerializers(serializers.ModelSerializer):
    property = serializers.SerializerMethodField()

    class Meta:
        model = RentalUnits
        fields = ('id', 'unit_number', 'property', 'no_of_bedrooms', 'no_of_bathrooms', 'rent_per_month', 'status',)

I wanted to show their foreign key names instead of IDs in a datatable and I found a good solution here so i ended up using

 def to_representation(self, instance):
        rep = super(RentalUnitsSerializers, self).to_representation(instance)
        rep['property'] = instance.property.property_name
        return rep

and it gave me this

{
        "id": 12,
        "unit_number": "1A",
        "property": 1,
        "no_of_bedrooms": 3,
        "no_of_bathrooms": 2,
        "rent_per_month": 60000,
        "status": "Occupied"
    },
{
        "id": 12,
        "unit_number": "1A",
        "property": "New Apartments",
        "no_of_bedrooms": 3,
        "no_of_bathrooms": 2,
        "rent_per_month": 60000,
        "status": "Occupied"
    },

Adding units & deleting units still works fine. My problem now comes up when I want to edit the rental unit details. I'm using jQuery and AJAX to populate my data table & forms via API. With the addition of def to_representation(self, instance): to the Rental Unit serializer, the data table populates with Foreign Key names, but the property field is left blank when the edit form loads, and the foreign key field name does not apprear in that input field. However, when I remove this def to_representation(self, instance): the property input field & data table is populated with the property Foreign Key and successful editing resumes. Here is my jQuery code for editing:

    //Edit Units API
    $('#RentalUnits-Records').on('click', '.update', function(e){
        e.preventDefault();
        
        let id = $(this).attr('id');
        $('input[id=unitID]').val(id);
        console.log(id)

        let myurl = "http://127.0.0.1:8000/api/units/"+id+"/";

        $.ajax({
            async: true,
            url:myurl,
            method:'GET',
            success: function(result){
                $('input[name="unit_number"]').val(result.unit_number);
                $('input[name="property"]').val(result.property);
                $('input[name="no_of_bedrooms"]').val(result.no_of_bedrooms);
                $('input[name="no_of_bathrooms"]').val(result.no_of_bathrooms);
                $('input[name="rent_per_month"]').val(result.rent_per_month);
                $('select[name="status"]').val(result.status);
            }
        });

        $( "#u-number" ).change(function() {
            $('input[name=unit_number]').val($(this).val());
        });
        $( "#u-property" ).change(function() {
            $('input[name=property]').val($(this).val());
        });
        $( "#u-bedrooms" ).change(function() {
            $('input[name=no_of_bedrooms]').val($(this).val());
        });
        $( "#u-bathrooms" ).change(function() {
            $('input[name=no_of_bathrooms]').val($(this).val());
        });
        $( "#u-rent" ).change(function() {
            $('input[name=rent_per_month]').val($(this).val());
        });
        $( "#u-status" ).change(function() {
            $('select[name=status]').val($(this).val());
        });

    });

    //Save Edited Rental Unit Button
    $(function() { 
            $('#editUnit').on('submit', function(e) { 
                e.preventDefault();  

                let id = $("#unitID").attr("value");
                console.log(id);

                let myurl = "http://127.0.0.1:8000/api/units/edit/"+id+"/";

            $.ajax({
                type : 'PUT',
                url : myurl,
                data : $("#editUnit :input").serializeArray(),
                dataType: "json",
                success: function(data){
                    alert("Unit Details Updated!");
                    location.reload();
                },
                error:function(data){
                    alert("Unit Details Not Updated!");
                    location.reload();
                }
            });
        });
    });
});

And the edit form:

<form id="editUnit" action="">
    {% csrf_token %}
    <div class="mb-3">
        <input type="hidden" id="unitID" value="">
    </div>
    <div class="mb-3">
        <label>Unit Number</label>
        <input type="text" class="form-control" name="unit_number" id="u-number" placeholder="Unit Number">
    </div>
    <div class="mb-3">
        <label>Associated Property</label>
        <input type="number" class="form-control" name="property" id="u-property" placeholder="Property" readonly>
    </div>
    <div class="mb-3">
        <label>No. of Bedrooms</label>
        <input type="number" class="form-control" name="no_of_bedrooms" id="u-bedrooms" placeholder="No. of Bedrooms">
    </div>
    <div class="mb-3">
        <label>No. of Bathrooms</label>
        <input type="number" class="form-control" name="no_of_bathrooms" id="u-bathrooms" placeholder="No. of Bathrooms">
    </div>
    <div class="mb-3">
        <label>Rent</label>
        <input type="number" class="form-control" name="rent_per_month" id="u-rent" placeholder="Rent Per Month">
    </div>
    <div class="mb-3">
        <label>Status</label>
        <select class="form-select" name="status" id="u-status" aria-label="Default select example" placeholder="Associated Property">
            <option selected disabled>Status</option>
            <option value="Occupied">Occupied</option>
            <option value="Under Maintenance">Under Maintenance</option>
            <option value="Vacant">Vacant</option>
        </select>
    </div>
    <div class="mb-3">
        <button class="btn btn-soft-success btn-sm" id="u-edit" type="submit">Save Changes</button>
        <button class="btn btn-soft-secondary btn-sm" type="button" data-bs-dismiss="modal">Cancel</button>
    </div>
</form>

QUESTION: How do I show the Foreign Key field name instead of ID in the data table and modal edit form but still maintain the property_id in the DB. I read somewhere it's bad practice to have foreign fields using strings instead of IDs?

ALSO some help in figuring out how to display the Properties in a dropdown list incase there is more than one property would be helpful to allow for a user to change that as well. As of now its readonly. Any help on this would be highly appreciated. Thank you.

CoderS
  • 143
  • 1
  • 8

1 Answers1

0

If you want to show any field of foreign key instead of id then you can use StringRelatedField.

for example:-

class RentalUnitsSerializers(serializers.ModelSerializer):
    property = serializers.StringRelatedField()
    class Meta:
        model = RentalUnits
       fields = ('id', 'unit_number', 'property', 'no_of_bedrooms', 
    'no_of_bathrooms', 'rent_per_month', 'status',)

This will show the value whatever you will be returning from str method of that model. you can check more about this from Documentation

Jaspreet singh
  • 346
  • 3
  • 9
  • this does not work for me. It prohibits my ability to add or delete units. Plus i read somewhere that `StringRelatedField()` is read only in nature. I still want to perform all CRUD functionalities. And so far I can CREATE, VIEW and DELETE. Its the EDIT part left. – CoderS Oct 13 '21 at 17:04
  • i think this should solve your problem. https://stackoverflow.com/a/64954011/11382420 – Jaspreet singh Oct 13 '21 at 18:12
  • thanks a lot! That helped a lot. I also found more here: https://stackoverflow.com/questions/17280007/retrieving-a-foreign-key-value-with-django-rest-framework-serializers – CoderS Oct 14 '21 at 08:27
  • glad to help you. – Jaspreet singh Oct 14 '21 at 13:36