Building a Project Budget Manager with Django – Part 3: Views and Templates

Building a Project Budget Manager with Django (9 Part Series)

1 Deploying a Django Application ON “pythonanywhere”.
2 Project Budget Manager Tutorial Series
5 more parts…
3 Part 7: Deploying to PythonAnywhere
4 Building a Project Budget Manager with Django – Part 6: Advanced Features
5 Building a Project Budget Manager with Django – Part 5: Templates and Documentation
6 Building a Project Budget Manager with Django – Part 4: Deployment and Production Setup On Ubuntu Server
7 Building a Project Budget Manager with Django – Part 3: Views and Templates
8 Building a Project Budget Manager with Django – Part 2: Authentication and Models
9 Building a Project Budget Manager with Django – Part 1: Project Setup and Structure

In this third part of our series, we’ll create views and templates for our Project Budget Manager. We’ll use Tailwind CSS for styling and HTMX for dynamic interactions.

Setting Up Tailwind CSS

  1. First, install Tailwind CSS dependencies:
npm <span>install</span> <span>-D</span> tailwindcss
npx tailwindcss init
npm <span>install</span> <span>-D</span> tailwindcss
npx tailwindcss init
npm install -D tailwindcss npx tailwindcss init

Enter fullscreen mode Exit fullscreen mode

  1. Create a tailwind.config.js file:
<span>/** @type {import('tailwindcss').Config} */</span>
<span>module</span><span>.</span><span>exports</span> <span>=</span> <span>{</span>
<span>content</span><span>:</span> <span>[</span>
<span>"</span><span>./templates/**/*.html</span><span>"</span><span>,</span>
<span>"</span><span>./static/**/*.js</span><span>"</span><span>,</span>
<span>],</span>
<span>theme</span><span>:</span> <span>{</span>
<span>extend</span><span>:</span> <span>{},</span>
<span>},</span>
<span>plugins</span><span>:</span> <span>[],</span>
<span>}</span>
<span>/** @type {import('tailwindcss').Config} */</span>
<span>module</span><span>.</span><span>exports</span> <span>=</span> <span>{</span>
  <span>content</span><span>:</span> <span>[</span>
    <span>"</span><span>./templates/**/*.html</span><span>"</span><span>,</span>
    <span>"</span><span>./static/**/*.js</span><span>"</span><span>,</span>
  <span>],</span>
  <span>theme</span><span>:</span> <span>{</span>
    <span>extend</span><span>:</span> <span>{},</span>
  <span>},</span>
  <span>plugins</span><span>:</span> <span>[],</span>
<span>}</span>
/** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./templates/**/*.html", "./static/**/*.js", ], theme: { extend: {}, }, plugins: [], }

Enter fullscreen mode Exit fullscreen mode

  1. Create static/css/input.css:
<span>@tailwind</span> <span>base</span><span>;</span>
<span>@tailwind</span> <span>components</span><span>;</span>
<span>@tailwind</span> <span>utilities</span><span>;</span>
<span>/* Custom styles */</span>
<span>@layer</span> <span>components</span> <span>{</span>
<span>.btn-primary</span> <span>{</span>
<span>@apply</span> <span>px-4</span> <span>py-2</span> <span>bg-blue-600</span> <span>text-white</span> <span>rounded-lg</span> <span>hover</span><span>:</span><span>bg-blue-700</span><span>;</span>
<span>}</span>
<span>.btn-secondary</span> <span>{</span>
<span>@apply</span> <span>px-4</span> <span>py-2</span> <span>bg-gray-600</span> <span>text-white</span> <span>rounded-lg</span> <span>hover</span><span>:</span><span>bg-gray-700</span><span>;</span>
<span>}</span>
<span>.form-input</span> <span>{</span>
<span>@apply</span> <span>mt-1</span> <span>block</span> <span>w-full</span> <span>rounded-md</span> <span>border-gray-300</span> <span>shadow-sm;</span>
<span>}</span>
<span>}</span>
<span>@tailwind</span> <span>base</span><span>;</span>
<span>@tailwind</span> <span>components</span><span>;</span>
<span>@tailwind</span> <span>utilities</span><span>;</span>

<span>/* Custom styles */</span>
<span>@layer</span> <span>components</span> <span>{</span>
  <span>.btn-primary</span> <span>{</span>
    <span>@apply</span> <span>px-4</span> <span>py-2</span> <span>bg-blue-600</span> <span>text-white</span> <span>rounded-lg</span> <span>hover</span><span>:</span><span>bg-blue-700</span><span>;</span>
  <span>}</span>
  <span>.btn-secondary</span> <span>{</span>
    <span>@apply</span> <span>px-4</span> <span>py-2</span> <span>bg-gray-600</span> <span>text-white</span> <span>rounded-lg</span> <span>hover</span><span>:</span><span>bg-gray-700</span><span>;</span>
  <span>}</span>
  <span>.form-input</span> <span>{</span>
    <span>@apply</span> <span>mt-1</span> <span>block</span> <span>w-full</span> <span>rounded-md</span> <span>border-gray-300</span> <span>shadow-sm;</span>
  <span>}</span>
<span>}</span>
@tailwind base; @tailwind components; @tailwind utilities; /* Custom styles */ @layer components { .btn-primary { @apply px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700; } .btn-secondary { @apply px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700; } .form-input { @apply mt-1 block w-full rounded-md border-gray-300 shadow-sm; } }

Enter fullscreen mode Exit fullscreen mode

Creating Base Templates

  1. Create templates/layout/base.html:
{% load static %}
<span><!DOCTYPE html></span>
<span><html</span> <span>lang=</span><span>"en"</span><span>></span>
<span><head></span>
<span><meta</span> <span>charset=</span><span>"UTF-8"</span><span>></span>
<span><meta</span> <span>name=</span><span>"viewport"</span> <span>content=</span><span>"width=device-width, initial-scale=1.0"</span><span>></span>
<span><title></span>{% block title %}Project Budget Manager{% endblock %}<span></title></span>
<span><link</span> <span>rel=</span><span>"stylesheet"</span> <span>href=</span><span>"{% static 'css/output.css' %}"</span><span>></span>
<span><script </span><span>src=</span><span>"{% static 'js/htmx.min.js' %}"</span> <span>defer</span><span>></script></span>
{% block extra_head %}{% endblock %}
<span></head></span>
<span><body</span> <span>class=</span><span>"bg-gray-50"</span><span>></span>
{% include "layout/nav.html" %}
<span><main</span> <span>class=</span><span>"container mx-auto px-4 py-8"</span><span>></span>
{% if messages %}
<span><div</span> <span>class=</span><span>"messages mb-8"</span><span>></span>
{% for message in messages %}
<span><div</span> <span>class=</span><span>"p-4 mb-4 rounded-lg {% if message.tags == 'success' %}bg-green-100 text-green-700{% elif message.tags == 'error' %}bg-red-100 text-red-700{% else %}bg-blue-100 text-blue-700{% endif %}"</span><span>></span>
{{ message }}
<span></div></span>
{% endfor %}
<span></div></span>
{% endif %}
{% block content %}{% endblock %}
<span></main></span>
<span><footer</span> <span>class=</span><span>"bg-gray-800 text-white py-8 mt-16"</span><span>></span>
<span><div</span> <span>class=</span><span>"container mx-auto px-4"</span><span>></span>
<span><p></span><span>&copy;</span> {% now "Y" %} Project Budget Manager. All rights reserved.<span></p></span>
<span></div></span>
<span></footer></span>
{% block extra_js %}{% endblock %}
<span></body></span>
<span></html></span>
{% load static %}
<span><!DOCTYPE html></span>
<span><html</span> <span>lang=</span><span>"en"</span><span>></span>
<span><head></span>
    <span><meta</span> <span>charset=</span><span>"UTF-8"</span><span>></span>
    <span><meta</span> <span>name=</span><span>"viewport"</span> <span>content=</span><span>"width=device-width, initial-scale=1.0"</span><span>></span>
    <span><title></span>{% block title %}Project Budget Manager{% endblock %}<span></title></span>
    <span><link</span> <span>rel=</span><span>"stylesheet"</span> <span>href=</span><span>"{% static 'css/output.css' %}"</span><span>></span>
    <span><script </span><span>src=</span><span>"{% static 'js/htmx.min.js' %}"</span> <span>defer</span><span>></script></span>
    {% block extra_head %}{% endblock %}
<span></head></span>
<span><body</span> <span>class=</span><span>"bg-gray-50"</span><span>></span>
    {% include "layout/nav.html" %}

    <span><main</span> <span>class=</span><span>"container mx-auto px-4 py-8"</span><span>></span>
        {% if messages %}
        <span><div</span> <span>class=</span><span>"messages mb-8"</span><span>></span>
            {% for message in messages %}
            <span><div</span> <span>class=</span><span>"p-4 mb-4 rounded-lg {% if message.tags == 'success' %}bg-green-100 text-green-700{% elif message.tags == 'error' %}bg-red-100 text-red-700{% else %}bg-blue-100 text-blue-700{% endif %}"</span><span>></span>
                {{ message }}
            <span></div></span>
            {% endfor %}
        <span></div></span>
        {% endif %}

        {% block content %}{% endblock %}
    <span></main></span>

    <span><footer</span> <span>class=</span><span>"bg-gray-800 text-white py-8 mt-16"</span><span>></span>
        <span><div</span> <span>class=</span><span>"container mx-auto px-4"</span><span>></span>
            <span><p></span><span>&copy;</span> {% now "Y" %} Project Budget Manager. All rights reserved.<span></p></span>
        <span></div></span>
    <span></footer></span>

    {% block extra_js %}{% endblock %}
<span></body></span>
<span></html></span>
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}Project Budget Manager{% endblock %}</title> <link rel="stylesheet" href="{% static 'css/output.css' %}"> <script src="{% static 'js/htmx.min.js' %}" defer></script> {% block extra_head %}{% endblock %} </head> <body class="bg-gray-50"> {% include "layout/nav.html" %} <main class="container mx-auto px-4 py-8"> {% if messages %} <div class="messages mb-8"> {% for message in messages %} <div class="p-4 mb-4 rounded-lg {% if message.tags == 'success' %}bg-green-100 text-green-700{% elif message.tags == 'error' %}bg-red-100 text-red-700{% else %}bg-blue-100 text-blue-700{% endif %}"> {{ message }} </div> {% endfor %} </div> {% endif %} {% block content %}{% endblock %} </main> <footer class="bg-gray-800 text-white py-8 mt-16"> <div class="container mx-auto px-4"> <p>&copy; {% now "Y" %} Project Budget Manager. All rights reserved.</p> </div> </footer> {% block extra_js %}{% endblock %} </body> </html>

Enter fullscreen mode Exit fullscreen mode

Creating Views

  1. Update app/views.py with our views:
<span>from</span> <span>django.shortcuts</span> <span>import</span> <span>render</span><span>,</span> <span>redirect</span><span>,</span> <span>get_object_or_404</span>
<span>from</span> <span>django.contrib.auth.decorators</span> <span>import</span> <span>login_required</span>
<span>from</span> <span>django.contrib</span> <span>import</span> <span>messages</span>
<span>from</span> <span>django.http</span> <span>import</span> <span>HttpResponse</span>
<span>from</span> <span>.models</span> <span>import</span> <span>Project</span><span>,</span> <span>Expense</span>
<span>from</span> <span>.forms</span> <span>import</span> <span>ProjectForm</span><span>,</span> <span>ExpenseForm</span>
<span>from</span> <span>decimal</span> <span>import</span> <span>Decimal</span>
<span>@login_required</span>
<span>def</span> <span>dashboard</span><span>(</span><span>request</span><span>):</span>
<span>user_projects</span> <span>=</span> <span>Project</span><span>.</span><span>objects</span><span>.</span><span>filter</span><span>(</span>
<span>created_by</span><span>=</span><span>request</span><span>.</span><span>user</span>
<span>).</span><span>order_by</span><span>(</span><span>'</span><span>-created_at</span><span>'</span><span>)</span>
<span>assigned_projects</span> <span>=</span> <span>Project</span><span>.</span><span>objects</span><span>.</span><span>filter</span><span>(</span>
<span>assigned_to</span><span>=</span><span>request</span><span>.</span><span>user</span>
<span>).</span><span>order_by</span><span>(</span><span>'</span><span>-created_at</span><span>'</span><span>)</span>
<span>context</span> <span>=</span> <span>{</span>
<span>'</span><span>user_projects</span><span>'</span><span>:</span> <span>user_projects</span><span>,</span>
<span>'</span><span>assigned_projects</span><span>'</span><span>:</span> <span>assigned_projects</span><span>,</span>
<span>}</span>
<span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/dashboard.html</span><span>'</span><span>,</span> <span>context</span><span>)</span>
<span>@login_required</span>
<span>def</span> <span>project_list</span><span>(</span><span>request</span><span>):</span>
<span>projects</span> <span>=</span> <span>Project</span><span>.</span><span>objects</span><span>.</span><span>filter</span><span>(</span>
<span>created_by</span><span>=</span><span>request</span><span>.</span><span>user</span>
<span>).</span><span>order_by</span><span>(</span><span>'</span><span>-created_at</span><span>'</span><span>)</span>
<span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/project_list.html</span><span>'</span><span>,</span> <span>{</span><span>'</span><span>projects</span><span>'</span><span>:</span> <span>projects</span><span>})</span>
<span>@login_required</span>
<span>def</span> <span>project_detail</span><span>(</span><span>request</span><span>,</span> <span>pk</span><span>):</span>
<span>project</span> <span>=</span> <span>get_object_or_404</span><span>(</span><span>Project</span><span>,</span> <span>pk</span><span>=</span><span>pk</span><span>)</span>
<span>expenses</span> <span>=</span> <span>project</span><span>.</span><span>expenses</span><span>.</span><span>all</span><span>().</span><span>order_by</span><span>(</span><span>'</span><span>-date</span><span>'</span><span>)</span>
<span>context</span> <span>=</span> <span>{</span>
<span>'</span><span>project</span><span>'</span><span>:</span> <span>project</span><span>,</span>
<span>'</span><span>expenses</span><span>'</span><span>:</span> <span>expenses</span><span>,</span>
<span>'</span><span>total_expenses</span><span>'</span><span>:</span> <span>project</span><span>.</span><span>get_total_expenses</span><span>(),</span>
<span>'</span><span>budget_remaining</span><span>'</span><span>:</span> <span>project</span><span>.</span><span>get_budget_remaining</span><span>(),</span>
<span>}</span>
<span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/project_detail.html</span><span>'</span><span>,</span> <span>context</span><span>)</span>
<span>@login_required</span>
<span>def</span> <span>project_create</span><span>(</span><span>request</span><span>):</span>
<span>if</span> <span>request</span><span>.</span><span>method</span> <span>==</span> <span>'</span><span>POST</span><span>'</span><span>:</span>
<span>form</span> <span>=</span> <span>ProjectForm</span><span>(</span><span>request</span><span>.</span><span>POST</span><span>)</span>
<span>if</span> <span>form</span><span>.</span><span>is_valid</span><span>():</span>
<span>project</span> <span>=</span> <span>form</span><span>.</span><span>save</span><span>(</span><span>commit</span><span>=</span><span>False</span><span>)</span>
<span>project</span><span>.</span><span>created_by</span> <span>=</span> <span>request</span><span>.</span><span>user</span>
<span>project</span><span>.</span><span>save</span><span>()</span>
<span>messages</span><span>.</span><span>success</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>Project created successfully.</span><span>'</span><span>)</span>
<span>return</span> <span>redirect</span><span>(</span><span>'</span><span>project_detail</span><span>'</span><span>,</span> <span>pk</span><span>=</span><span>project</span><span>.</span><span>pk</span><span>)</span>
<span>else</span><span>:</span>
<span>form</span> <span>=</span> <span>ProjectForm</span><span>()</span>
<span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/project_form.html</span><span>'</span><span>,</span> <span>{</span><span>'</span><span>form</span><span>'</span><span>:</span> <span>form</span><span>})</span>
<span>@login_required</span>
<span>def</span> <span>expense_create</span><span>(</span><span>request</span><span>,</span> <span>project_pk</span><span>):</span>
<span>project</span> <span>=</span> <span>get_object_or_404</span><span>(</span><span>Project</span><span>,</span> <span>pk</span><span>=</span><span>project_pk</span><span>)</span>
<span>if</span> <span>request</span><span>.</span><span>method</span> <span>==</span> <span>'</span><span>POST</span><span>'</span><span>:</span>
<span>form</span> <span>=</span> <span>ExpenseForm</span><span>(</span><span>request</span><span>.</span><span>POST</span><span>,</span> <span>request</span><span>.</span><span>FILES</span><span>)</span>
<span>if</span> <span>form</span><span>.</span><span>is_valid</span><span>():</span>
<span>expense</span> <span>=</span> <span>form</span><span>.</span><span>save</span><span>(</span><span>commit</span><span>=</span><span>False</span><span>)</span>
<span>expense</span><span>.</span><span>project</span> <span>=</span> <span>project</span>
<span>expense</span><span>.</span><span>created_by</span> <span>=</span> <span>request</span><span>.</span><span>user</span>
<span>expense</span><span>.</span><span>save</span><span>()</span>
<span>if</span> <span>request</span><span>.</span><span>htmx</span><span>:</span>
<span>return</span> <span>HttpResponse</span><span>(</span>
<span>f</span><span>'</span><span><div id=</span><span>"</span><span>expense-</span><span>{</span><span>expense</span><span>.</span><span>id</span><span>}</span><span>"</span><span> class=</span><span>"</span><span>expense-item</span><span>"</span><span>></span><span>'</span>
<span>f</span><span>'</span><span><p></span><span>{</span><span>expense</span><span>.</span><span>description</span><span>}</span><span> - $</span><span>{</span><span>expense</span><span>.</span><span>amount</span><span>}</span><span></p></div></span><span>'</span>
<span>)</span>
<span>messages</span><span>.</span><span>success</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>Expense added successfully.</span><span>'</span><span>)</span>
<span>return</span> <span>redirect</span><span>(</span><span>'</span><span>project_detail</span><span>'</span><span>,</span> <span>pk</span><span>=</span><span>project</span><span>.</span><span>pk</span><span>)</span>
<span>else</span><span>:</span>
<span>form</span> <span>=</span> <span>ExpenseForm</span><span>()</span>
<span>context</span> <span>=</span> <span>{</span>
<span>'</span><span>form</span><span>'</span><span>:</span> <span>form</span><span>,</span>
<span>'</span><span>project</span><span>'</span><span>:</span> <span>project</span><span>,</span>
<span>}</span>
<span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/expense_form.html</span><span>'</span><span>,</span> <span>context</span><span>)</span>
<span>from</span> <span>django.shortcuts</span> <span>import</span> <span>render</span><span>,</span> <span>redirect</span><span>,</span> <span>get_object_or_404</span>
<span>from</span> <span>django.contrib.auth.decorators</span> <span>import</span> <span>login_required</span>
<span>from</span> <span>django.contrib</span> <span>import</span> <span>messages</span>
<span>from</span> <span>django.http</span> <span>import</span> <span>HttpResponse</span>
<span>from</span> <span>.models</span> <span>import</span> <span>Project</span><span>,</span> <span>Expense</span>
<span>from</span> <span>.forms</span> <span>import</span> <span>ProjectForm</span><span>,</span> <span>ExpenseForm</span>
<span>from</span> <span>decimal</span> <span>import</span> <span>Decimal</span>

<span>@login_required</span>
<span>def</span> <span>dashboard</span><span>(</span><span>request</span><span>):</span>
    <span>user_projects</span> <span>=</span> <span>Project</span><span>.</span><span>objects</span><span>.</span><span>filter</span><span>(</span>
        <span>created_by</span><span>=</span><span>request</span><span>.</span><span>user</span>
    <span>).</span><span>order_by</span><span>(</span><span>'</span><span>-created_at</span><span>'</span><span>)</span>
    <span>assigned_projects</span> <span>=</span> <span>Project</span><span>.</span><span>objects</span><span>.</span><span>filter</span><span>(</span>
        <span>assigned_to</span><span>=</span><span>request</span><span>.</span><span>user</span>
    <span>).</span><span>order_by</span><span>(</span><span>'</span><span>-created_at</span><span>'</span><span>)</span>

    <span>context</span> <span>=</span> <span>{</span>
        <span>'</span><span>user_projects</span><span>'</span><span>:</span> <span>user_projects</span><span>,</span>
        <span>'</span><span>assigned_projects</span><span>'</span><span>:</span> <span>assigned_projects</span><span>,</span>
    <span>}</span>
    <span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/dashboard.html</span><span>'</span><span>,</span> <span>context</span><span>)</span>

<span>@login_required</span>
<span>def</span> <span>project_list</span><span>(</span><span>request</span><span>):</span>
    <span>projects</span> <span>=</span> <span>Project</span><span>.</span><span>objects</span><span>.</span><span>filter</span><span>(</span>
        <span>created_by</span><span>=</span><span>request</span><span>.</span><span>user</span>
    <span>).</span><span>order_by</span><span>(</span><span>'</span><span>-created_at</span><span>'</span><span>)</span>
    <span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/project_list.html</span><span>'</span><span>,</span> <span>{</span><span>'</span><span>projects</span><span>'</span><span>:</span> <span>projects</span><span>})</span>

<span>@login_required</span>
<span>def</span> <span>project_detail</span><span>(</span><span>request</span><span>,</span> <span>pk</span><span>):</span>
    <span>project</span> <span>=</span> <span>get_object_or_404</span><span>(</span><span>Project</span><span>,</span> <span>pk</span><span>=</span><span>pk</span><span>)</span>
    <span>expenses</span> <span>=</span> <span>project</span><span>.</span><span>expenses</span><span>.</span><span>all</span><span>().</span><span>order_by</span><span>(</span><span>'</span><span>-date</span><span>'</span><span>)</span>

    <span>context</span> <span>=</span> <span>{</span>
        <span>'</span><span>project</span><span>'</span><span>:</span> <span>project</span><span>,</span>
        <span>'</span><span>expenses</span><span>'</span><span>:</span> <span>expenses</span><span>,</span>
        <span>'</span><span>total_expenses</span><span>'</span><span>:</span> <span>project</span><span>.</span><span>get_total_expenses</span><span>(),</span>
        <span>'</span><span>budget_remaining</span><span>'</span><span>:</span> <span>project</span><span>.</span><span>get_budget_remaining</span><span>(),</span>
    <span>}</span>
    <span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/project_detail.html</span><span>'</span><span>,</span> <span>context</span><span>)</span>

<span>@login_required</span>
<span>def</span> <span>project_create</span><span>(</span><span>request</span><span>):</span>
    <span>if</span> <span>request</span><span>.</span><span>method</span> <span>==</span> <span>'</span><span>POST</span><span>'</span><span>:</span>
        <span>form</span> <span>=</span> <span>ProjectForm</span><span>(</span><span>request</span><span>.</span><span>POST</span><span>)</span>
        <span>if</span> <span>form</span><span>.</span><span>is_valid</span><span>():</span>
            <span>project</span> <span>=</span> <span>form</span><span>.</span><span>save</span><span>(</span><span>commit</span><span>=</span><span>False</span><span>)</span>
            <span>project</span><span>.</span><span>created_by</span> <span>=</span> <span>request</span><span>.</span><span>user</span>
            <span>project</span><span>.</span><span>save</span><span>()</span>
            <span>messages</span><span>.</span><span>success</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>Project created successfully.</span><span>'</span><span>)</span>
            <span>return</span> <span>redirect</span><span>(</span><span>'</span><span>project_detail</span><span>'</span><span>,</span> <span>pk</span><span>=</span><span>project</span><span>.</span><span>pk</span><span>)</span>
    <span>else</span><span>:</span>
        <span>form</span> <span>=</span> <span>ProjectForm</span><span>()</span>

    <span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/project_form.html</span><span>'</span><span>,</span> <span>{</span><span>'</span><span>form</span><span>'</span><span>:</span> <span>form</span><span>})</span>

<span>@login_required</span>
<span>def</span> <span>expense_create</span><span>(</span><span>request</span><span>,</span> <span>project_pk</span><span>):</span>
    <span>project</span> <span>=</span> <span>get_object_or_404</span><span>(</span><span>Project</span><span>,</span> <span>pk</span><span>=</span><span>project_pk</span><span>)</span>

    <span>if</span> <span>request</span><span>.</span><span>method</span> <span>==</span> <span>'</span><span>POST</span><span>'</span><span>:</span>
        <span>form</span> <span>=</span> <span>ExpenseForm</span><span>(</span><span>request</span><span>.</span><span>POST</span><span>,</span> <span>request</span><span>.</span><span>FILES</span><span>)</span>
        <span>if</span> <span>form</span><span>.</span><span>is_valid</span><span>():</span>
            <span>expense</span> <span>=</span> <span>form</span><span>.</span><span>save</span><span>(</span><span>commit</span><span>=</span><span>False</span><span>)</span>
            <span>expense</span><span>.</span><span>project</span> <span>=</span> <span>project</span>
            <span>expense</span><span>.</span><span>created_by</span> <span>=</span> <span>request</span><span>.</span><span>user</span>
            <span>expense</span><span>.</span><span>save</span><span>()</span>

            <span>if</span> <span>request</span><span>.</span><span>htmx</span><span>:</span>
                <span>return</span> <span>HttpResponse</span><span>(</span>
                    <span>f</span><span>'</span><span><div id=</span><span>"</span><span>expense-</span><span>{</span><span>expense</span><span>.</span><span>id</span><span>}</span><span>"</span><span> class=</span><span>"</span><span>expense-item</span><span>"</span><span>></span><span>'</span>
                    <span>f</span><span>'</span><span><p></span><span>{</span><span>expense</span><span>.</span><span>description</span><span>}</span><span> - $</span><span>{</span><span>expense</span><span>.</span><span>amount</span><span>}</span><span></p></div></span><span>'</span>
                <span>)</span>

            <span>messages</span><span>.</span><span>success</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>Expense added successfully.</span><span>'</span><span>)</span>
            <span>return</span> <span>redirect</span><span>(</span><span>'</span><span>project_detail</span><span>'</span><span>,</span> <span>pk</span><span>=</span><span>project</span><span>.</span><span>pk</span><span>)</span>
    <span>else</span><span>:</span>
        <span>form</span> <span>=</span> <span>ExpenseForm</span><span>()</span>

    <span>context</span> <span>=</span> <span>{</span>
        <span>'</span><span>form</span><span>'</span><span>:</span> <span>form</span><span>,</span>
        <span>'</span><span>project</span><span>'</span><span>:</span> <span>project</span><span>,</span>
    <span>}</span>
    <span>return</span> <span>render</span><span>(</span><span>request</span><span>,</span> <span>'</span><span>app/expense_form.html</span><span>'</span><span>,</span> <span>context</span><span>)</span>
from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib import messages from django.http import HttpResponse from .models import Project, Expense from .forms import ProjectForm, ExpenseForm from decimal import Decimal @login_required def dashboard(request): user_projects = Project.objects.filter( created_by=request.user ).order_by('-created_at') assigned_projects = Project.objects.filter( assigned_to=request.user ).order_by('-created_at') context = { 'user_projects': user_projects, 'assigned_projects': assigned_projects, } return render(request, 'app/dashboard.html', context) @login_required def project_list(request): projects = Project.objects.filter( created_by=request.user ).order_by('-created_at') return render(request, 'app/project_list.html', {'projects': projects}) @login_required def project_detail(request, pk): project = get_object_or_404(Project, pk=pk) expenses = project.expenses.all().order_by('-date') context = { 'project': project, 'expenses': expenses, 'total_expenses': project.get_total_expenses(), 'budget_remaining': project.get_budget_remaining(), } return render(request, 'app/project_detail.html', context) @login_required def project_create(request): if request.method == 'POST': form = ProjectForm(request.POST) if form.is_valid(): project = form.save(commit=False) project.created_by = request.user project.save() messages.success(request, 'Project created successfully.') return redirect('project_detail', pk=project.pk) else: form = ProjectForm() return render(request, 'app/project_form.html', {'form': form}) @login_required def expense_create(request, project_pk): project = get_object_or_404(Project, pk=project_pk) if request.method == 'POST': form = ExpenseForm(request.POST, request.FILES) if form.is_valid(): expense = form.save(commit=False) expense.project = project expense.created_by = request.user expense.save() if request.htmx: return HttpResponse( f'<div id="expense-{expense.id}" class="expense-item">' f'<p>{expense.description} - ${expense.amount}</p></div>' ) messages.success(request, 'Expense added successfully.') return redirect('project_detail', pk=project.pk) else: form = ExpenseForm() context = { 'form': form, 'project': project, } return render(request, 'app/expense_form.html', context)

Enter fullscreen mode Exit fullscreen mode

  1. Create app/forms.py:
<span>from</span> <span>django</span> <span>import</span> <span>forms</span>
<span>from</span> <span>.models</span> <span>import</span> <span>Project</span><span>,</span> <span>Expense</span>
<span>class</span> <span>ProjectForm</span><span>(</span><span>forms</span><span>.</span><span>ModelForm</span><span>):</span>
<span>class</span> <span>Meta</span><span>:</span>
<span>model</span> <span>=</span> <span>Project</span>
<span>fields</span> <span>=</span> <span>[</span><span>'</span><span>title</span><span>'</span><span>,</span> <span>'</span><span>description</span><span>'</span><span>,</span> <span>'</span><span>total_budget</span><span>'</span><span>,</span> <span>'</span><span>start_date</span><span>'</span><span>,</span> <span>'</span><span>end_date</span><span>'</span><span>,</span> <span>'</span><span>assigned_to</span><span>'</span><span>]</span>
<span>widgets</span> <span>=</span> <span>{</span>
<span>'</span><span>start_date</span><span>'</span><span>:</span> <span>forms</span><span>.</span><span>DateInput</span><span>(</span><span>attrs</span><span>=</span><span>{</span><span>'</span><span>type</span><span>'</span><span>:</span> <span>'</span><span>date</span><span>'</span><span>}),</span>
<span>'</span><span>end_date</span><span>'</span><span>:</span> <span>forms</span><span>.</span><span>DateInput</span><span>(</span><span>attrs</span><span>=</span><span>{</span><span>'</span><span>type</span><span>'</span><span>:</span> <span>'</span><span>date</span><span>'</span><span>}),</span>
<span>}</span>
<span>class</span> <span>ExpenseForm</span><span>(</span><span>forms</span><span>.</span><span>ModelForm</span><span>):</span>
<span>class</span> <span>Meta</span><span>:</span>
<span>model</span> <span>=</span> <span>Expense</span>
<span>fields</span> <span>=</span> <span>[</span><span>'</span><span>description</span><span>'</span><span>,</span> <span>'</span><span>amount</span><span>'</span><span>,</span> <span>'</span><span>category</span><span>'</span><span>,</span> <span>'</span><span>date</span><span>'</span><span>,</span> <span>'</span><span>receipt</span><span>'</span><span>]</span>
<span>widgets</span> <span>=</span> <span>{</span>
<span>'</span><span>date</span><span>'</span><span>:</span> <span>forms</span><span>.</span><span>DateInput</span><span>(</span><span>attrs</span><span>=</span><span>{</span><span>'</span><span>type</span><span>'</span><span>:</span> <span>'</span><span>date</span><span>'</span><span>}),</span>
<span>}</span>
<span>from</span> <span>django</span> <span>import</span> <span>forms</span>
<span>from</span> <span>.models</span> <span>import</span> <span>Project</span><span>,</span> <span>Expense</span>

<span>class</span> <span>ProjectForm</span><span>(</span><span>forms</span><span>.</span><span>ModelForm</span><span>):</span>
    <span>class</span> <span>Meta</span><span>:</span>
        <span>model</span> <span>=</span> <span>Project</span>
        <span>fields</span> <span>=</span> <span>[</span><span>'</span><span>title</span><span>'</span><span>,</span> <span>'</span><span>description</span><span>'</span><span>,</span> <span>'</span><span>total_budget</span><span>'</span><span>,</span> <span>'</span><span>start_date</span><span>'</span><span>,</span> <span>'</span><span>end_date</span><span>'</span><span>,</span> <span>'</span><span>assigned_to</span><span>'</span><span>]</span>
        <span>widgets</span> <span>=</span> <span>{</span>
            <span>'</span><span>start_date</span><span>'</span><span>:</span> <span>forms</span><span>.</span><span>DateInput</span><span>(</span><span>attrs</span><span>=</span><span>{</span><span>'</span><span>type</span><span>'</span><span>:</span> <span>'</span><span>date</span><span>'</span><span>}),</span>
            <span>'</span><span>end_date</span><span>'</span><span>:</span> <span>forms</span><span>.</span><span>DateInput</span><span>(</span><span>attrs</span><span>=</span><span>{</span><span>'</span><span>type</span><span>'</span><span>:</span> <span>'</span><span>date</span><span>'</span><span>}),</span>
        <span>}</span>

<span>class</span> <span>ExpenseForm</span><span>(</span><span>forms</span><span>.</span><span>ModelForm</span><span>):</span>
    <span>class</span> <span>Meta</span><span>:</span>
        <span>model</span> <span>=</span> <span>Expense</span>
        <span>fields</span> <span>=</span> <span>[</span><span>'</span><span>description</span><span>'</span><span>,</span> <span>'</span><span>amount</span><span>'</span><span>,</span> <span>'</span><span>category</span><span>'</span><span>,</span> <span>'</span><span>date</span><span>'</span><span>,</span> <span>'</span><span>receipt</span><span>'</span><span>]</span>
        <span>widgets</span> <span>=</span> <span>{</span>
            <span>'</span><span>date</span><span>'</span><span>:</span> <span>forms</span><span>.</span><span>DateInput</span><span>(</span><span>attrs</span><span>=</span><span>{</span><span>'</span><span>type</span><span>'</span><span>:</span> <span>'</span><span>date</span><span>'</span><span>}),</span>
        <span>}</span>
from django import forms from .models import Project, Expense class ProjectForm(forms.ModelForm): class Meta: model = Project fields = ['title', 'description', 'total_budget', 'start_date', 'end_date', 'assigned_to'] widgets = { 'start_date': forms.DateInput(attrs={'type': 'date'}), 'end_date': forms.DateInput(attrs={'type': 'date'}), } class ExpenseForm(forms.ModelForm): class Meta: model = Expense fields = ['description', 'amount', 'category', 'date', 'receipt'] widgets = { 'date': forms.DateInput(attrs={'type': 'date'}), }

Enter fullscreen mode Exit fullscreen mode

Creating Templates

  1. Create templates/app/dashboard.html:
{% extends "layout/base.html" %}
{% block title %}Dashboard - Project Budget Manager{% endblock %}
{% block content %}
<span><div</span> <span>class=</span><span>"grid grid-cols-1 md:grid-cols-2 gap-8"</span><span>></span>
<span><div></span>
<span><h2</span> <span>class=</span><span>"text-2xl font-bold mb-4"</span><span>></span>Your Projects<span></h2></span>
{% if user_projects %}
{% for project in user_projects %}
<span><div</span> <span>class=</span><span>"bg-white p-6 rounded-lg shadow-md mb-4"</span><span>></span>
<span><h3</span> <span>class=</span><span>"text-xl font-semibold mb-2"</span><span>></span>
<span><a</span> <span>href=</span><span>"{% url 'project_detail' pk=project.pk %}"</span> <span>class=</span><span>"text-blue-600 hover:text-blue-800"</span><span>></span>
{{ project.title }}
<span></a></span>
<span></h3></span>
<span><p</span> <span>class=</span><span>"text-gray-600 mb-2"</span><span>></span>{{ project.description|truncatewords:30 }}<span></p></span>
<span><div</span> <span>class=</span><span>"flex justify-between items-center"</span><span>></span>
<span><span</span> <span>class=</span><span>"text-sm text-gray-500"</span><span>></span>Budget: ${{ project.total_budget }}<span></span></span>
<span><span</span> <span>class=</span><span>"px-3 py-1 rounded-full text-sm {% if project.status == 'approved' %}bg-green-100 text-green-800 {% elif project.status == 'pending' %}bg-yellow-100 text-yellow-800 {% elif project.status == 'rejected' %}bg-red-100 text-red-800 {% else %}bg-gray-100 text-gray-800{% endif %}"</span><span>></span>
{{ project.get_status_display }}
<span></span></span>
<span></div></span>
<span></div></span>
{% endfor %}
{% else %}
<span><p</span> <span>class=</span><span>"text-gray-600"</span><span>></span>No projects created yet.<span></p></span>
{% endif %}
<span><a</span> <span>href=</span><span>"{% url 'project_create' %}"</span> <span>class=</span><span>"btn-primary inline-block mt-4"</span><span>></span>
Create New Project
<span></a></span>
<span></div></span>
<span><div></span>
<span><h2</span> <span>class=</span><span>"text-2xl font-bold mb-4"</span><span>></span>Assigned Projects<span></h2></span>
{% if assigned_projects %}
{% for project in assigned_projects %}
<span><div</span> <span>class=</span><span>"bg-white p-6 rounded-lg shadow-md mb-4"</span><span>></span>
<span><h3</span> <span>class=</span><span>"text-xl font-semibold mb-2"</span><span>></span>
<span><a</span> <span>href=</span><span>"{% url 'project_detail' pk=project.pk %}"</span> <span>class=</span><span>"text-blue-600 hover:text-blue-800"</span><span>></span>
{{ project.title }}
<span></a></span>
<span></h3></span>
<span><p</span> <span>class=</span><span>"text-gray-600 mb-2"</span><span>></span>{{ project.description|truncatewords:30 }}<span></p></span>
<span><div</span> <span>class=</span><span>"flex justify-between items-center"</span><span>></span>
<span><span</span> <span>class=</span><span>"text-sm text-gray-500"</span><span>></span>Created by: {{ project.created_by.get_full_name|default:project.created_by.username }}<span></span></span>
<span><span</span> <span>class=</span><span>"px-3 py-1 rounded-full text-sm {% if project.status == 'approved' %}bg-green-100 text-green-800 {% elif project.status == 'pending' %}bg-yellow-100 text-yellow-800 {% elif project.status == 'rejected' %}bg-red-100 text-red-800 {% else %}bg-gray-100 text-gray-800{% endif %}"</span><span>></span>
{{ project.get_status_display }}
<span></span></span>
<span></div></span>
<span></div></span>
{% endfor %}
{% else %}
<span><p</span> <span>class=</span><span>"text-gray-600"</span><span>></span>No projects assigned to you.<span></p></span>
{% endif %}
<span></div></span>
<span></div></span>
{% endblock %}
{% extends "layout/base.html" %}

{% block title %}Dashboard - Project Budget Manager{% endblock %}

{% block content %}
<span><div</span> <span>class=</span><span>"grid grid-cols-1 md:grid-cols-2 gap-8"</span><span>></span>
    <span><div></span>
        <span><h2</span> <span>class=</span><span>"text-2xl font-bold mb-4"</span><span>></span>Your Projects<span></h2></span>
        {% if user_projects %}
            {% for project in user_projects %}
            <span><div</span> <span>class=</span><span>"bg-white p-6 rounded-lg shadow-md mb-4"</span><span>></span>
                <span><h3</span> <span>class=</span><span>"text-xl font-semibold mb-2"</span><span>></span>
                    <span><a</span> <span>href=</span><span>"{% url 'project_detail' pk=project.pk %}"</span> <span>class=</span><span>"text-blue-600 hover:text-blue-800"</span><span>></span>
                        {{ project.title }}
                    <span></a></span>
                <span></h3></span>
                <span><p</span> <span>class=</span><span>"text-gray-600 mb-2"</span><span>></span>{{ project.description|truncatewords:30 }}<span></p></span>
                <span><div</span> <span>class=</span><span>"flex justify-between items-center"</span><span>></span>
                    <span><span</span> <span>class=</span><span>"text-sm text-gray-500"</span><span>></span>Budget: ${{ project.total_budget }}<span></span></span>
                    <span><span</span> <span>class=</span><span>"px-3 py-1 rounded-full text-sm {% if project.status == 'approved' %}bg-green-100 text-green-800 {% elif project.status == 'pending' %}bg-yellow-100 text-yellow-800 {% elif project.status == 'rejected' %}bg-red-100 text-red-800 {% else %}bg-gray-100 text-gray-800{% endif %}"</span><span>></span>
                        {{ project.get_status_display }}
                    <span></span></span>
                <span></div></span>
            <span></div></span>
            {% endfor %}
        {% else %}
            <span><p</span> <span>class=</span><span>"text-gray-600"</span><span>></span>No projects created yet.<span></p></span>
        {% endif %}

        <span><a</span> <span>href=</span><span>"{% url 'project_create' %}"</span> <span>class=</span><span>"btn-primary inline-block mt-4"</span><span>></span>
            Create New Project
        <span></a></span>
    <span></div></span>

    <span><div></span>
        <span><h2</span> <span>class=</span><span>"text-2xl font-bold mb-4"</span><span>></span>Assigned Projects<span></h2></span>
        {% if assigned_projects %}
            {% for project in assigned_projects %}
            <span><div</span> <span>class=</span><span>"bg-white p-6 rounded-lg shadow-md mb-4"</span><span>></span>
                <span><h3</span> <span>class=</span><span>"text-xl font-semibold mb-2"</span><span>></span>
                    <span><a</span> <span>href=</span><span>"{% url 'project_detail' pk=project.pk %}"</span> <span>class=</span><span>"text-blue-600 hover:text-blue-800"</span><span>></span>
                        {{ project.title }}
                    <span></a></span>
                <span></h3></span>
                <span><p</span> <span>class=</span><span>"text-gray-600 mb-2"</span><span>></span>{{ project.description|truncatewords:30 }}<span></p></span>
                <span><div</span> <span>class=</span><span>"flex justify-between items-center"</span><span>></span>
                    <span><span</span> <span>class=</span><span>"text-sm text-gray-500"</span><span>></span>Created by: {{ project.created_by.get_full_name|default:project.created_by.username }}<span></span></span>
                    <span><span</span> <span>class=</span><span>"px-3 py-1 rounded-full text-sm {% if project.status == 'approved' %}bg-green-100 text-green-800 {% elif project.status == 'pending' %}bg-yellow-100 text-yellow-800 {% elif project.status == 'rejected' %}bg-red-100 text-red-800 {% else %}bg-gray-100 text-gray-800{% endif %}"</span><span>></span>
                        {{ project.get_status_display }}
                    <span></span></span>
                <span></div></span>
            <span></div></span>
            {% endfor %}
        {% else %}
            <span><p</span> <span>class=</span><span>"text-gray-600"</span><span>></span>No projects assigned to you.<span></p></span>
        {% endif %}
    <span></div></span>
<span></div></span>
{% endblock %}
{% extends "layout/base.html" %} {% block title %}Dashboard - Project Budget Manager{% endblock %} {% block content %} <div class="grid grid-cols-1 md:grid-cols-2 gap-8"> <div> <h2 class="text-2xl font-bold mb-4">Your Projects</h2> {% if user_projects %} {% for project in user_projects %} <div class="bg-white p-6 rounded-lg shadow-md mb-4"> <h3 class="text-xl font-semibold mb-2"> <a href="{% url 'project_detail' pk=project.pk %}" class="text-blue-600 hover:text-blue-800"> {{ project.title }} </a> </h3> <p class="text-gray-600 mb-2">{{ project.description|truncatewords:30 }}</p> <div class="flex justify-between items-center"> <span class="text-sm text-gray-500">Budget: ${{ project.total_budget }}</span> <span class="px-3 py-1 rounded-full text-sm {% if project.status == 'approved' %}bg-green-100 text-green-800 {% elif project.status == 'pending' %}bg-yellow-100 text-yellow-800 {% elif project.status == 'rejected' %}bg-red-100 text-red-800 {% else %}bg-gray-100 text-gray-800{% endif %}"> {{ project.get_status_display }} </span> </div> </div> {% endfor %} {% else %} <p class="text-gray-600">No projects created yet.</p> {% endif %} <a href="{% url 'project_create' %}" class="btn-primary inline-block mt-4"> Create New Project </a> </div> <div> <h2 class="text-2xl font-bold mb-4">Assigned Projects</h2> {% if assigned_projects %} {% for project in assigned_projects %} <div class="bg-white p-6 rounded-lg shadow-md mb-4"> <h3 class="text-xl font-semibold mb-2"> <a href="{% url 'project_detail' pk=project.pk %}" class="text-blue-600 hover:text-blue-800"> {{ project.title }} </a> </h3> <p class="text-gray-600 mb-2">{{ project.description|truncatewords:30 }}</p> <div class="flex justify-between items-center"> <span class="text-sm text-gray-500">Created by: {{ project.created_by.get_full_name|default:project.created_by.username }}</span> <span class="px-3 py-1 rounded-full text-sm {% if project.status == 'approved' %}bg-green-100 text-green-800 {% elif project.status == 'pending' %}bg-yellow-100 text-yellow-800 {% elif project.status == 'rejected' %}bg-red-100 text-red-800 {% else %}bg-gray-100 text-gray-800{% endif %}"> {{ project.get_status_display }} </span> </div> </div> {% endfor %} {% else %} <p class="text-gray-600">No projects assigned to you.</p> {% endif %} </div> </div> {% endblock %}

Enter fullscreen mode Exit fullscreen mode

Setting Up URLs

Update app/urls.py:

<span>from</span> <span>django.urls</span> <span>import</span> <span>path</span>
<span>from</span> <span>.</span> <span>import</span> <span>views</span>
<span>app_name</span> <span>=</span> <span>'</span><span>app</span><span>'</span>
<span>urlpatterns</span> <span>=</span> <span>[</span>
<span>path</span><span>(</span><span>''</span><span>,</span> <span>views</span><span>.</span><span>dashboard</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>dashboard</span><span>'</span><span>),</span>
<span>path</span><span>(</span><span>'</span><span>projects/</span><span>'</span><span>,</span> <span>views</span><span>.</span><span>project_list</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>project_list</span><span>'</span><span>),</span>
<span>path</span><span>(</span><span>'</span><span>projects/create/</span><span>'</span><span>,</span> <span>views</span><span>.</span><span>project_create</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>project_create</span><span>'</span><span>),</span>
<span>path</span><span>(</span><span>'</span><span>projects/<int:pk>/</span><span>'</span><span>,</span> <span>views</span><span>.</span><span>project_detail</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>project_detail</span><span>'</span><span>),</span>
<span>path</span><span>(</span><span>'</span><span>projects/<int:project_pk>/expenses/create/</span><span>'</span><span>,</span>
<span>views</span><span>.</span><span>expense_create</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>expense_create</span><span>'</span><span>),</span>
<span>]</span>
<span>from</span> <span>django.urls</span> <span>import</span> <span>path</span>
<span>from</span> <span>.</span> <span>import</span> <span>views</span>

<span>app_name</span> <span>=</span> <span>'</span><span>app</span><span>'</span>

<span>urlpatterns</span> <span>=</span> <span>[</span>
    <span>path</span><span>(</span><span>''</span><span>,</span> <span>views</span><span>.</span><span>dashboard</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>dashboard</span><span>'</span><span>),</span>
    <span>path</span><span>(</span><span>'</span><span>projects/</span><span>'</span><span>,</span> <span>views</span><span>.</span><span>project_list</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>project_list</span><span>'</span><span>),</span>
    <span>path</span><span>(</span><span>'</span><span>projects/create/</span><span>'</span><span>,</span> <span>views</span><span>.</span><span>project_create</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>project_create</span><span>'</span><span>),</span>
    <span>path</span><span>(</span><span>'</span><span>projects/<int:pk>/</span><span>'</span><span>,</span> <span>views</span><span>.</span><span>project_detail</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>project_detail</span><span>'</span><span>),</span>
    <span>path</span><span>(</span><span>'</span><span>projects/<int:project_pk>/expenses/create/</span><span>'</span><span>,</span> 
         <span>views</span><span>.</span><span>expense_create</span><span>,</span> <span>name</span><span>=</span><span>'</span><span>expense_create</span><span>'</span><span>),</span>
<span>]</span>
from django.urls import path from . import views app_name = 'app' urlpatterns = [ path('', views.dashboard, name='dashboard'), path('projects/', views.project_list, name='project_list'), path('projects/create/', views.project_create, name='project_create'), path('projects/<int:pk>/', views.project_detail, name='project_detail'), path('projects/<int:project_pk>/expenses/create/', views.expense_create, name='expense_create'), ]

Enter fullscreen mode Exit fullscreen mode

Next Steps

In Part 4 of this series, we’ll:

  • Implement project approval workflow
  • Add email notifications
  • Create project reports and analytics
  • Set up production deployment

Resources


This article is part of the “Building a Project Budget Manager with Django” series. Check out Part 1 and Part 2 if you haven’t already!

Building a Project Budget Manager with Django (9 Part Series)

1 Deploying a Django Application ON “pythonanywhere”.
2 Project Budget Manager Tutorial Series
5 more parts…
3 Part 7: Deploying to PythonAnywhere
4 Building a Project Budget Manager with Django – Part 6: Advanced Features
5 Building a Project Budget Manager with Django – Part 5: Templates and Documentation
6 Building a Project Budget Manager with Django – Part 4: Deployment and Production Setup On Ubuntu Server
7 Building a Project Budget Manager with Django – Part 3: Views and Templates
8 Building a Project Budget Manager with Django – Part 2: Authentication and Models
9 Building a Project Budget Manager with Django – Part 1: Project Setup and Structure

原文链接:Building a Project Budget Manager with Django – Part 3: Views and Templates

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
better late than never.
只要开始,虽晚不迟
评论 抢沙发

请登录后发表评论

    暂无评论内容