aman goyal
aman goyal

Reputation: 301

Make django query from database based on two models

I am working on search page in which doctor can search for patient with name ,start_date and end_date. Here start_date and end_date are the date range in which any document was uploaded. The result should return all the patients whose name is name and has documents uploaded between start_date and end_date.

class Document(models.Model):
    name = models.CharField(max_length=15, blank=True)
    document = models.FileField(upload_to='documents/')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    patient = models.ForeignKey(to=Patient, on_delete=models.CASCADE, unique=False)
    
    class Meta:
        unique_together = ('name', 'document', 'patient')

    # many document can have same patient

    def __str__(self) -> str:
        return f'{self.name}'
    
    def __repr__(self) -> str:
        return f'{self.name}'

class Patient(models.Model):
    # required fields
    first_name = models.CharField(max_length=55, blank=False, null=False)
    last_name = models.CharField(max_length=55, blank=False, null=False)
    email = models.EmailField(max_length=255, blank=False, null=False, unique=True)
    
    # not required fields
    address = models.TextField(max_length=255, blank=True, null=True)
    postal_zip = models.IntegerField(max_length=255, blank=True, null=True)
    city = models.CharField(max_length=255, blank=True, null=True)
    country = models.CharField(max_length=255, blank=True, null=True)
    phone_number = models.IntegerField(max_length=17, blank=True, null=True) # mobile
    alternate_number = models.IntegerField(max_length=17, blank=True, null=True) # alternate

    def __str__(self) -> str:
        return f"{self.first_name} {self.last_name}"
    
    def __repr__(self) -> str:
        return f"{self.first_name} {self.last_name}"

I can get all documents uploaded between particular dates like this

documents  = Document.objects.filter(
                    uploaded_at__gte=start_date
                ).intersection(
                    Document.objects.filter(uploaded_at__lte=end_date)
                )

but I cant figure out a way to combine above result with this

query = Patient.objects.filter(
                    Q(first_name__icontains=search_key)         |
                    Q(last_name__icontains=search_key)          |   
                    Q(email__icontains=search_key)              |
                    Q(city__icontains=search_key)               |
                    Q(phone_number__icontains=search_key)       |
                    Q(alternate_number__icontains=search_key)   |
                    Q(country__icontains=search_key)           
    
                )

Upvotes: 1

Views: 43

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476554

You can use double underscores to look through a relation, so here we can filter on Patients which have a document in the given range:

# Patients which match the search_key, and have
# documents uploaded in the (start_date, end_date) range

query = Patient.objects.filter(
    Q(first_name__icontains=search_key) |
    Q(last_name__icontains=search_key) |
    Q(email__icontains=search_key) |
    Q(city__icontains=search_key) |
    Q(phone_number__icontains=search_key) |
    Q(alternate_number__icontains=search_key) |
    Q(country__icontains=search_key),
    document__uploaded_at__range=(start_date, end_date)
).distinct()

The .distinct() here prevents, as you commented, that you retrieve the same patient multiple times (once per Document in the range).

or Documents that have a Patient that matches the given conditions:

# Documents uploaded in the (start_date, end_date) range
# which match a Patient with the search_key.

query = Document.objects.filter(
    Q(patient__first_name__icontains=search_key) |
    Q(patient__last_name__icontains=search_key) |
    Q(patient__email__icontains=search_key) |
    Q(patient__city__icontains=search_key) |
    Q(patient__phone_number__icontains=search_key) |
    Q(patient__alternate_number__icontains=search_key) |
    Q(patient__country__icontains=search_key),
    uploaded_at__range=(start_date, end_date)
)

Upvotes: 1

Related Questions