0

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'
Shehzad009
  • 1,547
  • 6
  • 28
  • 42

2 Answers2

2

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 %}
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • `client_contract_number` looks like a number to me. `client_number` doesn't though. – Dominic Rodger Jan 05 '11 at 10:46
  • @Dominic Roger: There are two fields called `client_contract_number`. The one in the `Invoice` model is a ForeignKey, the one in `Contract` is an integer. – Daniel Roseman Jan 05 '11 at 10:49
  • I think I tried something like this before but it didn't work. I think it was how I wrote it in my views.py. What would I need in my views? – Shehzad009 Jan 05 '11 at 10:53
  • @Shehzad009: you don't need anything, just what I posted above. If you are having a particular problem, please post the code you've used and the full traceback. – Daniel Roseman Jan 05 '11 at 11:09
  • Ok I think I got it finally. I hope it works throught my code though.In my views I got somthing like this: "invoice_name = invoices_list[0].client_contract_number.client_number.name". In addition I have also used your printing method as well in my template. – Shehzad009 Jan 05 '11 at 12:45
0
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.

Josh Smeaton
  • 47,939
  • 24
  • 129
  • 164
  • Basically I want to display a table where in one column will show all invoice id. There should be in another column which shows all clients names. However The correct invoice id has to match with the correct client name in the same row. – Shehzad009 Jan 05 '11 at 12:18
  • @Sheh I understand what you're trying to do. The accepted answer is correct. You should be getting the client name via the invoice by spanning multiple relationships using the dot syntax. That should be done in the template. Not in your view. As you iterate over the invoices, you need to extract that invoices client name attribute. My advice on select_related is still good advice though. Use select_related in your view, and access the client name in the template. – Josh Smeaton Jan 05 '11 at 21:49