简体   繁体   中英

How to get field name instead of foreign id in django

In my django app, i have four model tables linked using foreign keys, the problem is, when i make a query for any model table, the fields that are linked through foreign keys are returned as id's instead of the name.

My way does not work.

My customers models.py file

1st model

class Customer(models.Model):
    name = models.CharField(max_length=50)
    phone = models.CharField(max_length=20, unique=True)
    email = models.EmailField(max_length=255, unique=True, blank=True)
    image = models.ImageField(default='default.png', upload_to='customer_photos/%Y/%m/%d/')
    data_added = models.DateField(default=datetime.now, blank=True)

    def __str__(self):
        return self.name

2nd model

class ShippingAddress(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="customer_ship_address")
    description = models.TextField(blank=True)   
    frequent_customer = models.BooleanField(default=False)
    address = models.CharField(max_length=50, blank=True)
    zip_code = models.CharField(max_length=12, blank=True)
    location = models.CharField(max_length=255)

    def __str__(self):
        return self.customer.name

3rd model - PaymentInvoice

class paymentInvoice(models.Model):

    shipping_address_owner = models.ForeignKey(
        ShippingAddress, on_delete=models.CASCADE, related_name="customer_invoice")
    product = models.ManyToManyField(
        Product, related_name='product_invoice')
    mode = models.CharField(max_length=20, choices=paymentMode.choices, default=paymentMode.MPESA)
    date = models.DateField(default=datetime.now)
    invoice_id = models.CharField(
        max_length=50, unique=True, default=increment_invoice_number)
    quantity = models.PositiveSmallIntegerField()
    status = models.CharField(
        max_length=20, choices=paymentStatus.choices, default=paymentStatus.PENDING)
    payment_made = models.DecimalField(max_digits=20, decimal_places=2)

    def __str__(self):
        return self.shipping_address_owner.customer.name

My Products models.py file

class Product(models.Model):
    slug = models.CharField(max_length=200, unique=True)
    name = models.CharField(max_length=200)
    available = models.BooleanField(default=True)
    description = models.TextField(blank=True)
    image = models.ImageField(default='default_product.jpg', upload_to='product_photos')
    category = models.CharField(max_length=200)
    qty_amount = models.CharField(
        max_length=20, choices=Qty_Choices, default='250ml')
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __str__(self):
        return self.name

My PaymentInvoice views.py file

class paymentInvoiceListCreateView(ListCreateAPIView):
    """
    ListCreateAPIView executes both 'GET' and 'POST' requests. i.e listing a queryset or creating a model instance.
    """
    serializer_class = paymentInvoiceSerializer
    queryset = paymentInvoice.objects.all().order_by(
        '-date').values(shipping_address_owner__customer)

When i make the above query the api returns the following, where the product field and shipping_address_owner field are just id's. I need there respective names instead.

{
    "count": 6,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 9,
            "mode": "Mpesa",
            "date": "2020-07-27",
            "invoice_id": "INV-0006",
            "quantity": 1,
            "status": "Pending",
            "payment_made": "500.00",
            "shipping_address_owner": 9,
            "product": [
                1
            ]
        },

EDIT: paymentInvoiceSerializer

class paymentInvoiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = paymentInvoice
        fields = '__all__'

You need to make some changes to your serializer.

If you just need the name and nothing more:

class paymentInvoiceSerializer(serializers.ModelSerializer):
    product = serializers.SerializerMethodField()
    shipping_address_owner = serializers.SerializerMethodField()

    class Meta:
        model = paymentInvoice
        fields = '__all__'
    
    def get_product(self, instance):
        names = []
        for product in instance.product.all():
            names.append(product.name)
        return names
    
    def get_shipping_address_owner(self, instance):
        return instance.shipping_address_owner.customer.name

You can also create different serializer for each model and pass them to their fields to get the full serialized data for them. It would be something like this:

ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

And then in your payment serializer:

class paymentInvoiceSerializer(serializers.ModelSerializer):
    product = ProductSerializer()

    class Meta:
        model = paymentInvoice
        fields = '__all__'

You can do the same for shipping_address_owner .

You can try like this in your serializer.

class paymentInvoiceSerializer(serializers.ModelSerializer):
    shipping_address_owner = serializers.CharField(source='shipping_address_owner.customer')
    class Meta:
        model = paymentInvoice
        fields = ['shipping_address_owner',...]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM