Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homework #8

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 8 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,12 @@
# MelbDjango School Lesson Four

### Assignment 1

**Important:** Check out our first assignment here: https://github.com/melbdjango/melbdjango-assignment

---


Congratulations, you've made it to the git repository for our fourth lesson. Hopefully you also made it to the class
and some of this makes sense to you.

Check our RESOURCES.md for some links we think you'll find handy.


## Homework Checklist

- [ ] [Fork this repository][gh-fork]
- [ ] Clone the repo to your own machine
- [ ] Use the virtualenv you created in previous lesson
- [ ] Create forms to create new Projects and Clients (look at our EntryForm to see how to handle ForeignKey relationships)
- [ ] Add those forms to your views and templates so that users can create new Clients and Projects
- [ ] Add some validation to make sure that start time is in the past
- [ ] Validate that the end time is after the start time
- [X] [Fork this repository][gh-fork]
- [X] Clone the repo to your own machine
- [X] Use the virtualenv you created in previous lesson
- [X] Create forms to create new Projects and Clients (look at our EntryForm to see how to handle ForeignKey relationships)
- [X] Add those forms to your views and templates so that users can create new Clients and Projects
- [X] Add some validation to make sure that start time is in the past
- [X] Validate that the end time is after the start time
- [ ] Bonus Points #1: Think about making our form look a little nice with some CSS
- [ ] Bonus Points #2: Add the ability to edit existing Projects and Clients

When you've completed some or all of the homework please make a [Pull Request][gh-pr] against this repository. If you submit
your work before Wednesday evening we'll give you feedback before the next class.

If you'd like help, make a Pull Request with your incomplete work and ask a question to @darrenfrenkel, @sesh or
@funkybob.


## Displaying the class slides

Install reveal-md with npm and use that to display the class slides.

```
npm install -g reveal-md
```

From within the `lesson-four` repo:

```
cd slides
reveal-md CLASS.md --theme melbdjango
```
- [X] Bonus Points #2: Add the ability to edit existing Projects and Clients

[gh-fork]: https://help.github.com/articles/fork-a-repo/
[gh-pr]: https://help.github.com/articles/using-pull-requests/
[dj-request-response]: https://docs.djangoproject.com/en/1.8/ref/request-response/
[mdn-html]: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Introduction
1 change: 0 additions & 1 deletion formexample/formexample/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import formapp.views


urlpatterns = [
url(r'^$', formapp.views.example, name='html_form'),
url(r'^django-form/$', formapp.views.django_example, name='django_form'),
Expand Down
2 changes: 1 addition & 1 deletion slides/CLASS.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class HelloWorldForm(forms.Form):
- It takes two optional arguments for validation
- `max_length`
- `min_length`

```
class HelloWorldForm(forms.Form):
name = forms.CharField(label="Say Hello", required=True)
Expand Down
32 changes: 28 additions & 4 deletions timetracker/entries/forms.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
from django import forms

from .models import Project

from django.utils import timezone
from .models import Project, Client

class EntryForm(forms.Form):
start = forms.DateTimeField(label="Start Time", help_text="Format: 2006-10-25 14:30")
end = forms.DateTimeField(label="End Time", help_text="Format: 2006-10-25 14:30")
stop = forms.DateTimeField(label="End Time", help_text="Format: 2006-10-25 14:30")
project = forms.ModelChoiceField(queryset=Project.objects.all())
description = forms.CharField()

def clean(self):
cleaned_start = super(EntryForm,self).clean()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to call super().

start = cleaned_start.get("start")
stop = cleaned_start.get("stop")

if start and stop:
if start > timezone.now():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could do the validation for the start time not being in the future in clean_start().

raise forms.ValidationError("Error:Project date exceeds current date")
return start

if stop < start:
raise forms.ValidationError("Error: Project end date is before start date")
return stop

class ClientForm(forms.Form):
name = forms.CharField(required=False, label="name")

class ProjectForm(forms.Form):
client= forms.ModelChoiceField(queryset=Client.objects.all())
name = forms.CharField(required=False, label="name")




3 changes: 1 addition & 2 deletions timetracker/entries/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class Client(models.Model):
name = models.CharField(max_length=200)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should avoid trailing spaces.

def __str__(self):
return self.name

Expand All @@ -16,7 +16,6 @@ class Project(models.Model):
def __str__(self):
return '<{}> {}'.format(self.client, self.name)


# Create your models here.
class Entry(models.Model):
start = models.DateTimeField(default=timezone.now)
Expand Down
16 changes: 16 additions & 0 deletions timetracker/entries/templates/client_edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% extends "base.html" %}

{% block title %}Clients{% endblock %}

{% block content %}
<h2>Clients</h2>
<form method="post">
{% csrf_token %}
{{ client_form.as_p }}
<input type="submit" name="client_submit" value="Update Client">
</form>

<ul>
<li>{{ client.name }}</li>
</ul>
{% endblock %}
8 changes: 7 additions & 1 deletion timetracker/entries/templates/clients.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@

{% block content %}
<h2>Clients</h2>
<form method="post">
{% csrf_token %}
{{ client_form.as_p }}
<input type="submit" name="client_submit" value="Create Client">
</form>

<ul>
{% for client in client_list %}
<li><a href="{% url 'client-detail' pk=client.pk %}">{{ client.name }}</a></li>
<li>{{ client.name }}</li>
{% endfor %}
</ul>
{% endblock %}
10 changes: 5 additions & 5 deletions timetracker/entries/templates/entries.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

{% block content %}
<h2>Entries</h2>
<form method="post">
{% csrf_token %}
{{ entry_form.as_p }}
<input type="submit" name="name" value="Create Entry">
</form>
<form method="post">
{% csrf_token %}
{{ entry_form.as_p }}
<input type="submit" name="project_name" value="Create Entry">
</form>

<ul>
{% for entry in entry_list %}
Expand Down
16 changes: 16 additions & 0 deletions timetracker/entries/templates/project_edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% extends "base.html" %}

{% block title %}Projects{% endblock %}

{% block content %}
<h2>Projects</h2>
<form method="post">
{% csrf_token %}
{{ project_form.as_p }}
<input type="submit" name="test" value="Update Project">
</form>

<ul>
<li>{{ project.name }}</li>
</ul>
{% endblock %}
11 changes: 9 additions & 2 deletions timetracker/entries/templates/projects.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@

{% block content %}
<h2>Projects</h2>
<ul>
<form method="post">
{% csrf_token %}
{{ project_form.as_p }}
<input type="submit" name="test" value="Create Project">
</form>

<ul>
{% for project in project_list %}
<li>{{ project.name }} (<a href="{% url 'client-detail' pk=project.client.pk %}">{{ project.client.name }}</a>)</li>
<li>{{ project.name }}</li>
<li>{{ project.client}}
{% endfor %}
</ul>
{% endblock %}
3 changes: 3 additions & 0 deletions timetracker/entries/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
urlpatterns = [
url(r'^clients/$', views.clients, name='client-list'),
url(r'^clients/(?P<pk>\d+)/$', views.client_detail, name='client-detail'),
url(r'^clients/(?P<pk>\d+)/edit/$', views.client_edit, name='client-edit'),
url(r'^entries/$', views.entries, name='entry-list'),
url(r'^projects/$', views.projects, name='project-list'),
url(r'^projects/(?P<pk>\d+)/edit/$', views.project_edit, name='project-edit'),
]

65 changes: 57 additions & 8 deletions timetracker/entries/views.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,54 @@
from django.shortcuts import render, get_object_or_404
from django.utils import timezone

from .forms import EntryForm
from .models import Client, Entry, Project
from .forms import EntryForm, ProjectForm, ClientForm

from .models import Client, Entry, Project

def clients(request):
if request.method == 'POST':
client_form = ClientForm(request.POST)
if client_form.is_valid():
client = Client()
client.name = client_form.cleaned_data['name']
client.save()
else:
client_form = ClientForm(request.POST)

client_list = Client.objects.all()
return render(request, 'clients.html', {
'client_list': client_list,
'client_form': client_form,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really make any difference, but most people only use "form" as the name in the template and the naming you chose when they have more than one form.

})


def client_detail(request, pk):
client = get_object_or_404(Client, pk=pk)
return render(request, 'client_detail.html', {
'client': client,
})

def client_edit(request,pk):
client = get_object_or_404(Client, pk=pk)
if request.method == 'POST':
client_form = ClientForm(request.POST)
if client_form.is_valid():
client.name = client_form.cleaned_data['name']
client.save()
else:
client_form = ClientForm(initial={'name':client.name})

return render(request, 'client_edit.html', {
'client': client,
'client_form': client_form,
})

def entries(request):
if request.method == 'POST':
# Create our form object with our POST data
entry_form = EntryForm(request.POST)
if entry_form.is_valid():
# If the form is valid, let's create and Entry with the submitted data
entry = Entry()
entry.start = entry_form.cleaned_data['start']
entry.end = entry_form.cleaned_data['end']
entry.stop = entry_form.cleaned_data['stop']
entry.project = entry_form.cleaned_data['project']
entry.description = entry_form.cleaned_data['description']
entry.save()
Expand All @@ -39,9 +61,36 @@ def entries(request):
'entry_form': entry_form,
})


def projects(request):
if request.method == 'POST':
project_form = ProjectForm(request.POST)
if project_form.is_valid():
project = Project()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also write

project = Project(
    name=project_form.cleaned_data['name'],
    client=project_form.cleaned_data['client'],
)
project.save()

or use Project.objects.create(...) to spare the explicit project.save() call.

project.client = project_form.cleaned_data['client']
project.name = project_form.cleaned_data['name']
project.save()
else:
project_form = ProjectForm(request.POST)

project_list = Project.objects.all()
return render(request, 'projects.html', {
return render(request,'projects.html',{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous code (the one marked red) was correct according to PEP 8. , are almost always followed by a single whitespace.

'project_list': project_list,
'project_form': project_form,
})

def project_edit(request,pk):
project = get_object_or_404(Project, pk=pk)
if request.method == 'POST':
project_form = ProjectForm(request.POST)
if project_form.is_valid():
project.client = project_form.cleaned_data['client']
project.name = project_form.cleaned_data['name']
project.save()
else:
project_form = ProjectForm(initial={'name':project.name})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't pass a project as initial value here, thus a user has to select the value from the drop down list each time they want to edit a project.


return render(request, 'project_edit.html', {
'project': project,
'project_form': project_form,
})