Home > OS >  How to display data from parent model using foreign key django
How to display data from parent model using foreign key django

Time:10-08

I want to display the child model data with the parent model data as well in a queryset.

This is my models in model.py

class Shareholders(models.Model):
    sharehold_IC = models.CharField(primary_key=True, unique=True, validators=[RegexValidator(r'^\d{12,12}$'), only_int], max_length=12)
    sharehold_name = models.CharField(max_length=100, null=True)
    sharehold_email = models.CharField(max_length=50, null=True, unique=True)
    sharehold_address = models.TextField(null=True, blank=True)
    password = models.CharField(max_length=100)

    def __str__(self):
        return self.sharehold_name

class Meeting(models.Model):

    MEETING_STATUS = (
        ('Coming Soon', 'Coming Soon'),
        ('Live', 'Live'),
        ('Closed', 'Closed')

    )
    meeting_ID = models.CharField(primary_key=True, max_length=6, validators=[RegexValidator(r'^\d{6,6}$')])
    meeting_title = models.CharField(max_length=400, null=True)
    meeting_date = models.DateField()
    meeting_time = models.TimeField()
    meeting_desc = models.CharField(max_length=500, null=True)

    meeting_status = models.CharField(max_length=200, null=True, choices=MEETING_STATUS)
    date_created = models.DateTimeField(default=timezone.now, null=True)
    


    def __str__(self):
        return self.meeting_ID


class Question(models.Model):
    question_ID = models.AutoField(primary_key=True)
    question = models.CharField(max_length=400, null=True)
    meeting_id = models.ForeignKey(Meeting, on_delete=CASCADE)
    shareholder_IC = models.ForeignKey(Shareholders_Meeting, on_delete=CASCADE, related_name='shareholder_ic')
    date_created = models.DateTimeField(default=timezone.now, null=True)


    def __str__(self):
        return str(self.meeting_id)

I try to display all the data from the Question model with the shareholders details such as sharehold_name from the Shareholders model. This is how I try to do in Views.py.

Views.py

def getMessages(response, meeting_id):
    meeting = Meeting.objects.get(meeting_ID=meeting_id)
    questions = Question.objects.filter(meeting_id=meeting.meeting_ID)
    # print(list(questions.values('shareholder_IC_id')))
    for i in questions:
        print(i.shareholder_ic.all())
    
    return JsonResponse({"questions":list(questions.values())})

But somehow I got this error AttributeError: 'Question' object has no attribute 'shareholder_ic'. I want to get the result like this:

{'question_ID': 141, 'question': "I'm good. How are you?", 'meeting_id_id': '731404', 'shareholder_IC_id': '122311221231', 'date_created': datetime.datetime(2021, 10, 7, 3, 40, 12, 160029, tzinfo=<UTC>), 'sharehold_name':'John Steve', 'sharehold_email':'[email protected]'}

How do I fix this or is there any other way to display the data? Thanks in advance

CodePudding user response:

You must use backward relations

questions = Question.shareholder_ic.filter(meeting_id=meeting.meeting_ID)

Do not touch it on the object

For other settings, create the required query set in manager

CodePudding user response:

To begin with, you're not using the related_name attribute in your Question model correctly. It's not to use an alternative name to refer to the related model, the opposite, it's the name you want to use to refer to the Question model from the related model, Shareholders in your case. You have to remake your model:

class Question(models.Model):
    question_ID = models.AutoField(primary_key=True)
    question = models.CharField(max_length=400, null=True)
    meeting_id = models.ForeignKey(Meeting, on_delete=CASCADE)
    shareholder_IC = models.ForeignKey(Shareholders_Meeting, on_delete=CASCADE, related_name='questions')
    date_created = models.DateTimeField(default=timezone.now, null=True)


    def __str__(self):
        return str(self.meeting_id)

Then, in your views.py you need to use the correct attribute name in the Question model, which is shareholders_IC:

def getMessages(request, meeting_id):  # <- Shouldn't the first param be request?
    meeting = Meeting.objects.get(meeting_ID=meeting_id)
    # No need to use meeting.meeting_ID here, you can use the meeting instance
    questions = Question.objects.filter(meeting_id=meeting)
    for i in questions:
        print(i.shareholder_IC)  # <- No .all(), a question has only one shareholder
    
    return JsonResponse({"questions":list(questions.values())})

However, to achieve what you want, you should either use Django REST Framework, or serialize yourself the different instances that you'll get:

def getMessages(request, meeting_id):
    meeting = Meeting.objects.get(meeting_ID=meeting_id)
    questions = Question.objects.filter(meeting_id=meeting)
    questions_list = []
    for i in questions:
        questions_list.append(
            {
                "question_ID": i.question_ID,
                "question": i.question,
                "shareholder_IC_id": i.shareholder_IC.shareholder_IC,
                ...
            }
        )
    
    return JsonResponse(questions_list)

I would recommend two main things:

  1. Learn about relationships in Django and how to represent them in your models. You shouldn't have an attribute meeting_id, for example, in your Question. Although internally the id is indeed being used to query the Meeting, the attribute has a relationship to the model, not to the ID.
  2. Use DRF. It will really help you a lot.
  • Related