Shehzad009
Shehzad009

Reputation: 1607

Django question on querysets

I have another Django/python question. I have a models.py which look something like this.

class Client(models.Model):
 client_number = models.PositiveIntegerField()
 name = models.CharField(max_length=80)
 address = models.CharField(max_length=250)
 telephone = models.CharField(max_length=20)
 fax = models.CharField(max_length=20)
 email = models.EmailField()
 alternative_name = models.CharField(max_length=80, blank=True, null=True)
 alternative_address = models.CharField(max_length=250, blank=True, null=True)
 alternative_telephone = models.CharField(max_length=20, blank=True, null=True)
 alternative_email = models.EmailField(blank=True, null=True)
 def __unicode__(self):
         return unicode(self.client_number)

class Contract(models.Model):
 client_number = models.ForeignKey(Client)
 client_contract_number = models.PositiveIntegerField()
 start_date = models.DateField()
 end_date = models.DateField()
 contract_type = models.IntegerField(verbose_name = "Contract Types", choices = CONTRACT_TYPE_CHOICES) 
 contract_status =models.IntegerField(verbose_name = "Contract Status", choices = CONTRACT_STATUS_CHOICES) 
 exception = models.DecimalField(max_digits=5, decimal_places=2)
 uplift_percentage = models.DecimalField(max_digits=5, decimal_places=2)
 payment_day = models.DateField()
 payment_type = models.IntegerField(verbose_name = "Payment Type", choices = PAYMENT_TYPE_CHOICES)
 late_payment = models.IntegerField(verbose_name = "Late Payment Change", choices = LATE_PAYMENT_CHOICES) 
 late_payment_change_rate = models.DecimalField(max_digits=5, decimal_places=2)
 contract_value = models.DecimalField(max_digits=20, decimal_places=2)
 monthly_value = models.DecimalField(max_digits=20, decimal_places=2)

 def __unicode__(self):
         return unicode (self.client_contract_number)


    class Invoice(models.Model):
     transaction_type = models.IntegerField(verbose_name = "Transaction type", choices = TRANSACTION_TYPE_CHOICES) 
     invoice_number = models.CharField(max_length=16)
     date = models.DateField() 
     client_contract_number = models.ForeignKey(Contract)
     invoice_contact = models.CharField(max_length=80)
     invoice_net = models.DecimalField(max_digits=16, decimal_places=2)
     invoice_vat = models.DecimalField(max_digits=16, decimal_places=2)
     invoice_gross = models.DecimalField(max_digits=16, decimal_places=2)
     payment_date = models.DateField()
     special_notes = models.CharField(max_length=128)

     def __unicode__(self):
             return self.invoice_number

I know in django if I look for {{invoices.client_contract_number }}, I get the client contract number. But supposing I wanted to know for a particular invoice, how would I look up the clients name is? I cannot do {{invoice.name}}, because there is no foregin key value for client in invoice.

Edit: Here is my views

@login_required
def homepage(request):
    invoices_list = Invoice.objects.all()
    invoice_name = invoices_list.client_contract_number.client_number.name
    return render_to_response(('index.html', locals()), {'invoices_list': invoices_list }, context_instance=RequestContext(request))

And error.

'QuerySet' object has no attribute 'client_contract_number'

Upvotes: 0

Views: 387

Answers (2)

Daniel Roseman
Daniel Roseman

Reputation: 599450

You can follow the relationship across two joins:

invoice.client_contract_number.client_number.name

By the way, your field names are confusing. client_contract_number isn't a number, it's a Contract. And client_number isn't a number either, it's a Client. Just call them client_contract and client.

Edit after question update

I'm not sure what you're trying to do here. invoices_list is a queryset of all invoices - obviously it doesn't make sense to ask what the client name is for that list. Presumably what you actually want to do is iterate through - probably in your template - and print out the name for each one:

{% for invoice in invoices_list %}
    Client name: {{ client_contract_number.client_number.name }}
{% endfor %}

Upvotes: 2

Josh Smeaton
Josh Smeaton

Reputation: 48710

def homepage(request):
    invoices_list = Invoice.objects.all()
    invoice_name = invoices_list.client_contract_number.client_number.name
    return render_to_response(('index.html', locals()), {'invoices_list': invoices_list }, context_instance=RequestContext(request))

You can't get the client name from a LIST of invoices. Is there a particular invoice that you're interested in?

When you have an instance of an invoice, then you can do invoice.client_contract_number.client_number.name. But you can't do it on a list!

By the way, if you're going to be traversing multiple joins, make sure your query set has a select_related clause.

invoices_list = Invoice.objects.select_related(depth=3).all()

That will ensure that only one big query is executed up front, rather than potentially hundreds if you're iterating through a list, then doing a 3 relation query for each object. Any time you have more than 1 dot (invoice.client is one dot), strongly consider using select_related.

Upvotes: 0

Related Questions