sqlearner
sqlearner

Reputation: 65

Newbie - Django Project with Multiple Apps - Unable to render Views

I am in process of developing a Django Project that has 3 apps namely Customer, Investments and Stocks. Each Customer can have multiple Investments and Stocks but not the other way round. So far, everything works well on Admin side of the application. I am able to CRUD as an admin, but my goal is to have a 3 separate user levels - customer, advisor and admin (this is working fine!). A customer can only view his/her profile, investments and stocks pertaining to it. An advisor can view information of multiple customers and their portfolios. I think I can separate these by different Authentication levels/restrictions. These are my files,

This is my customer model,

    from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User


class Customer(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=200)
    cust_number = models.AutoField(max_length=5, primary_key=True)
    city = models.CharField(max_length=50)
    state = models.CharField(max_length=50)
    zipcode = models.CharField(max_length=10)
    email = models.CharField(max_length=200)
    home_phone = models.CharField(max_length=50)
    cell_phone = models.CharField(max_length=50)
    created_date = models.DateTimeField(
        default=timezone.now)
    updated_date = models.DateTimeField(
        blank=True, null=True)

    def created(self):
        self.created_date = timezone.now()
        self.save()

    def updated(self):
        self.updated_date = timezone.now()
        self.save()

    def __str__(self):
        return self.name

This is my investment model,

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User


class Investment(models.Model):
    category = models.CharField(max_length=50)
    description = models.CharField(max_length=200)
    cust_number = models.ForeignKey('customers.Customer')
    acquired_value = models.DecimalField(max_digits=10, decimal_places=2)
    acquired_date = models.DateTimeField(default=timezone.now)
    recent_value = models.DecimalField(max_digits=10, decimal_places=2)
    recent_date = models.DateTimeField(default=timezone.now, blank=True, null=True)

    def created(self):
        self.acquired_date = timezone.now()
        self.save()

    def updated(self):
        self.recent_date = timezone.now()
        self.save()

    def __str__(self):
        return self.category

This is my stocks model,

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User


class Stock(models.Model):
    symbol = models.CharField(max_length=10)
    name = models.CharField(max_length=50)
    shares = models.CharField(max_length=50)
    cust_number = models.ForeignKey('customers.Customer')
    purchase_price = models.DecimalField(max_digits=10, decimal_places=2)
    recent_date = models.DateTimeField(default=timezone.now, blank=True, null=True)

    def created(self):
        self.recent_date = timezone.now()
        self.save()

    def __str__(self):
        return self.name

This is my views.py in customers app although have separate views for investments and stocks, I defined same classes in customers/views.py so it renders in single view.

from django.shortcuts import render
from django.utils import timezone
from .models import Customer
from investments.models import Investment
from stocks.models import Stock


def customer(request):
    customers = Customer.objects.filter(created_date__lte=timezone.now())
    return render(request, 'customers/customer.html', {'customers': customers})


def investment(request):
    investments = Investment.objects.filter(created_date__lte=timezone.now())
    return render(request, 'customers/customer.html', {'investments': investments})


def stock(request):
    stocks = Stock.objects.filter(created_date__lte=timezone.now())
    return render(request, 'customers/customer.html', {'stocks': stocks})

I am trying to render the views on single html page like this,

Here's my customer.html template

{% load staticfiles %}
<!DOCTYPE html>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<link href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">

<html lang="en">

<head>
  <link rel="stylesheet" href="{% static 'css/customers.css' %}">
  <meta charset="UTF-8">
  <title>Eagle Financial Services</title>
</head>

<body>
  <div class="container">
    <div class="row">
      <div class="col-md-10 col-md-offset-1">
        <div class="panel panel-primary">
          <div class="panel-heading">Welcome!</div>
          <div class="panel-body">
            ABC Financial Services, your Financial Services Partner.
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="row">
    <h2 style="padding-left: 15Px">Customer Information</h2>
  </div>
  <div>
    <table class="table table-striped table-bordered table-hover">
      <thead>
        <tr class="bg-info">
          <th>Customer ID</th>
          <th>Name</th>
          <th>Address</th>
          <th>City</th>
          <th>State</th>
          <th>Zip</th>
          <th>Primary Email</th>
          <th>Home Phone</th>
          <th>Cell Phone</th>
          <th colspan="3">Actions</th>
        </tr>
      </thead>
      <tbody>
        {% for customer in customers %}
        <tr>
          <td>{{ customer.cust_number }}</td>
          <td>{{ customer.name }}</td>
          <td>{{ customer.address }}</td>
          <td>{{ customer.city }}</td>
          <td>{{ customer.state }}</td>
          <td>{{ customer.zipcode }}</td>
          <td>{{ customer.email }}</td>
          <td>{{ customer.home_phone }}</td>
          <td>{{ customer.cell_phone }}</td>
          <td><a href="{{ customers.customer }}" class="btn btn-primary">Read</a></td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
  </div>

  <div class="row">
    <h2 style="padding-left: 15Px">Investments Information</h2>
  </div>
  <div>
    <table class="table table-striped table-bordered table-hover">
      <thead>
        <tr class="bg-info">
          <th>Customer ID</th>
          <th>Name</th>
          <th>Category</th>
          <th>Description</th>
          <th>Acquired Value</th>
          <th>Acquired Date</th>
          <th>Recent Value</th>
          <th>Recent Date</th>
          <th colspan="3">Actions</th>
        </tr>
      </thead>
      <tbody>
        {% for customer in customers %}
        <tr>
          <td>{{ customer.cust_number }}</td>
          <td>{{ customer.name }}</td>
          {% for investment in investments %}
          <td>{{ investment.category }}</td>
          <td>{{ investment.description }}</td>
          <td>{{ investment.acquired_value }}</td>
          <td>{{ investment.acquired_date }}</td>
          <td>{{ investment.recent_value }}</td>
          <td>{{ investment.recent_date }}</td>
          {% endfor %} {% endfor %}

      </tbody>
    </table>
  </div>

  <div class="row">
    <h2 style="padding-left: 15Px">Stocks Information</h2>
  </div>
  <div>
    <table class="table table-striped table-bordered table-hover">
      <thead>
        <tr class="bg-info">
          <th>Symbol</th>
          <th>Name</th>
          <th>Shares</th>
          <th>Cust_Number</th>
          <th>Purchase Price</th>
          <th>Recent Date</th>
          <th colspan="3">Actions</th>
        </tr>
      </thead>
      <tbody>
        {% for stock in stocks %}
        <tr>
          <td>{{ stock.symbol }}</td>
          <td>{{ stock.name }}</td>
          <td>{{ stock.shares }}</td>
          <td>{{ stock.cust_number }}</td>
          <td>{{ stock.purchase_price }}</td>
          <td>{{ stock.recent_date }}</td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
  </div>

</body>

</html>

Here's projectname.url

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', include('customers.urls')),
    url(r'', include('investments.urls')),
    url(r'', include('stocks.urls')),
]

Here's customers.url

`from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.customer, name='customer'),
]`

Investment and Stocks resemble customer.urls except the name.

Now on the webpage, only the values in customer table are being displayed, and in investment table only cust_number and name are being displayed nothing else and in stocks nothing is displayed. I have tried almost all the trial/errors for past 3 days. I am lot confused. Where I am getting it wrong. Any guidance will be highly appreciated. Thanks.

I am using Python - 3.6, Django - 1.11.1.

Upvotes: 1

Views: 121

Answers (2)

Pythonista
Pythonista

Reputation: 11635

In your template your attempting to iterate three different templates variables, passed in through the dict to render, which are being served by three different views. Why would you expect all of them to render when using a specific one of these views when you haven't passed this variable to the template for rendering by the server before it's displayed to the client?

The only reason you get some data in the investments table (referencing data to customers) is because it's referencing the data on a customer object from the outer (containing) forloop iterating the customer objects you passed in.

Specifically you're serving:

def customer(request):

    customers = Customer.objects.filter(created_date__lte=timezone.now())
    return render(request, 'customers/customer.html', {'customers': customers})

as the home view '^$' which has a list of customer objects as the template variable customers which is rendering the data in your {% for customer in curstomers %} loops

Alternative Approach:

Unless there's something preventing you from changing the schema to this... which I don't see why there would be. You can just add a ForeignKey to stocks and investments to denote that specific customers stocks and investments rather than having your data as sparse as it is (although.. that's occasionally a good thing).

Example:

class Customer(models.Model):

    ...
    created = models.DateTimeField(default=timezone.now)
    **updated = models.DateTimeField(auto_now_add=True)**
    stock = models.ForeignKey(Stock, related_name="stocks")
    investment = models.ForeignKey(Investment, related_name="investments")

Changes:

You can reference these as customer.stock_set.(filter / all etc) on an instance. Similarly for investment, or you can use customer.stocks using the related name. Additionally you can also use prefetch_related if you wanted.

Note the auto_now_add=True on updated you can use this for timestamps rather than manually updating them since it will change the time to be the time it was saved on each successive save of the model instance.

Get rid of the foreign keys on stocks and investments.

Additional:

Why not have a OneToOneField on your customer referencing a User model instance to define a custom user model representing customers?

Upvotes: 1

Arpit Solanki
Arpit Solanki

Reputation: 9931

The reason why you are facing this problem is that views.customer only passes the information of customer and not the other variables like stocks. So in your customer/views.py:

def customer(request):
    customers = Customer.objects.filter(created_date__lte=timezone.now())
    investments = Investment.objects.filter(created_date__lte=timezone.now())
    stocks = Stock.objects.filter(created_date__lte=timezone.now())
    return render(request, 'customers/customer.html', {'customers': customers, 'stocks': stock, 'investments', investments})

Upvotes: 1

Related Questions