Skip to content

Instantly share code, notes, and snippets.

@sivaa
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sivaa/0087d76ccd14fe9117a4 to your computer and use it in GitHub Desktop.
Save sivaa/0087d76ccd14fe9117a4 to your computer and use it in GitHub Desktop.
#### Step 0: Movie app Creation & Registration ####
# Create a demo app
python manage.py startapp movie
# Create a 'templates' directory under fav/movie/ folder
mkdir movie/templates
# Registred this app in the INSTALLED_APPS tuple in fav/fav/settings.py
'movie',
#### Step 1: Create Movie Add HTML Form ####
# Create fav/movie/templates/movies.html file with the following content
<!DOCTYPE html>
<html>
<head>
<title>My Fav Movie List</title>
</head>
<body>
<form action="/movies/" method="post">
Movie Name : <input type="text" name="movie_name"/>
<input type="submit" value="Add"/>
</form>
</body>
</html>
# Serve this template in the fav/movie/views.py
def movies(request):
return render(request, "movies.html")
# Open fav/fav/urls.py and create a routing for the above view
url(r'^movies/$', 'movie.views.movies'),
# Access the following URLs in the browser
http://localhost:8000/movies/
# Click "Add" button
# Fix the CSRF verification by providing the token inside the form
<form action="/movies/" method="post"> {% csrf_token %}
#### Step 2: Implement Add functionality and Store it in Database ####
# We are using SQLite database and the settings.py wil have the following settings by default
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Create a model (database table) to store the movie name in fav/movie/models.py
class Movie(models.Model):
name = models.CharField(max_length = 100, unique = True)
# Create the above table using syncdb
python manage.py syncdb
# It will not create the tables since from 1.7 database/table migration is enabled by default
# Perform the migration using the following steps
python manage.py makemigrations
python manage.py migrate
# [OPTIONAL] Verify the table structure in SQLite browser
# Access this table in the Django shell and try the following options
# Open the shell
python manage.py shell
# Import the Movie model
from movie.models import Movie
# Count the number of available records
Movie.objects.count()
# Create the first record
Movie.objects.create(name = "Troy")
# Create few more records
Movie.objects.create(name = "Terminator")
Movie.objects.create(name = "Avatar")
Movie.objects.create(name = "Ice Age")
# List all the records
Movie.objects.all()
# Fix the object representation in models.py
class Movie(models.Model):
name = models.CharField(max_length = 100, unique = True)
def __unicode__(self):
return self.name
# Changes won't be auto reflected. Quit the shell (Ctrl + Z) and reopen it
# Import the model and list all the records
from movie.models import Movie
Movie.objects.all()
# Fetch the first record
Movie.objects.first()
# Fetch the last record
Movie.objects.last()
# Count the number of available records
Movie.objects.count()
# Fetch a specific record using get API
troy_movie = Movie.objects.get(name="Troy")
# Access its fields
troy_movie.name
troy_movie.id
troy_movie.pk
# Fetch list of matching records using filter API
Movie.objects.filter(name__contains = "T")
# Exclude a specific record
Movie.objects.exclude(name__contains = "T")
Movie.objects.exclude(name__contains = "t")
# Chain multiple APIs
Movie.objects.filter(name__contains = "a").exclude(name__contains = " ")
# Delete a specific record
troy_movie = Movie.objects.get(name="Troy")
troy_movie.delete()
# Delete all records
Movie.objects.all().delete()
# Explore all the others APIs from this link https://docs.djangoproject.com/en/dev/ref/models/querysets/
# Handle POST request, extract the movie_name and persist in database
from django.http import HttpResponse
from movie.models import Movie (or) from .models import Movie
def movies(request):
if request.method == 'GET':
return render(request, "movies.html")
if request.method == 'POST':
movie_name = request.POST.get("movie_name")
Movie.objects.create(name = movie_name)
message = "Movie '{}' is added successfully.".format(movie_name)
return HttpResponse(message)
return ("Invalid Request")
# Test this feature by adding a movie name in the browser.
#### Step 3: Implement the notification message in the same page ####
# Add the message variable in the template
<body>
{% if message %}
{{ message }} <br> <br>
{% endif %}
# <HTML From>
</body>
# Pass the message variable to template
if request.method == 'POST':
# Other lines
return render(request,
"movies.html",
{"message" : message})
#### Step 4: List all the available movies before Add form ####
# Display the movies list in the HTML
<body>
# <Notification Message>
{% if movies %}
{% for movie in movies %}
<li> {{ movie.name }} </li>
{% endfor %}
{% else %}
No movies added so far. <br>
{% endif %} <br>
# <HTML Form>
</body>
# Pass the movies list from views to template
def _get_movies():
return Movie.objects.all()
def movies(request):
if request.method == 'GET':
return render(request,
"movies.html",
{"movies" : _get_movies()})
if request.method == 'POST':
# Other lines
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies()})
#### Step 5: Implement Remove feature in HTTP GET ####
# Add the remove link before each movie name
{% for movie in movies %}
<li> <a href="/movie/remove/?id={{ movie.pk }}"> [x] </a> {{ movie.name }} </li>
{% endfor %}
# Implement the routing for remove option in urls.py
url(r'^movie/remove/$', 'movie.views.remove_movie'),
# Remove the selected movie name from the persistence
def remove_movie(request):
if request.method == 'GET':
movie_id = request.GET.get("id")
movie = Movie.objects.get(id = movie_id)
movie.delete()
message = "Movie '{}' is removed successfully.".format(movie.name)
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies()})
return ("Invalid Request")
#### Step 6: Validations, Integrity and other Error ####
# Implement movie length validation and handle IntegrityError
from django.db.utils import IntegrityError
def movies(request):
# GET implementation
if request.method == 'POST':
movie_name = request.POST.get("movie_name")
movie_name = movie_name.strip()
if not movie_name:
message = "Enter a Movie Name"
elif len(movie_name) < 3:
message = "Not enough words!"
else:
try:
Movie.objects.create(name = movie_name)
message = "Movie '{}' is added successfully.".format(movie_name)
except IntegrityError:
message = "Movie '{}' is already exists.".format(movie_name)
# Remaining code here
# Handle the invalid movie id in the remove method
try:
movie = Movie.objects.get(id = movie_id)
movie.delete()
message = "Movie '{}' is removed successfully.".format(movie.name)
except Movie.DoesNotExist as e:
message = "Given movie does not exists."
#### Step 7: Implement Django Forms and remove HTML Form ####
# Create fav/movie/forms.py and implement Django Form
from django import forms
class MovieForm(forms.Form):
movie_name = forms.CharField(required = False)
# Enhance the 'movies' view to use the above form
def movies(request):
if request.method == 'GET':
return render(request,
"movies.html",
{"movies" : _get_movies(),
"form" : MovieForm()}) # Added
if request.method == 'POST':
form = MovieForm(request.POST)
if form.is_valid():
movie_name = form.cleaned_data["movie_name"]
# Remaining code
try:
Movie.objects.create(name = movie_name)
message = "Movie '{}' is added successfully.".format(movie_name)
form = MovieForm() # Added
except IntegrityError:
message = "Movie '{}' is already exists.".format(movie_name)
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies(),
"form" : form}) # Added
# Enhance the 'remove_movie' view to use the django form
def remove_movie(request):
# Other code
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies(),
"form" : MovieForm()}) # Added
# Enhance the template to use the django form
<form action="/movies/" method="post"> {% csrf_token %}
{{ form }}
<input type="submit" value="Add">
</form>
#### Step 8: Move Validations from views to Django Form ####
# Implement the validations in the Django form
class MovieForm(forms.Form):
movie_name = forms.CharField(required = True)
def clean_movie_name(self):
movie_name = self.cleaned_data['movie_name'].strip()
if len(movie_name) < 3:
raise forms.ValidationError("Not enough words!")
return movie_name
# Remove the validations from views
if request.method == 'POST':
form = MovieForm(request.POST)
if form.is_valid():
movie_name = form.cleaned_data["movie_name"].strip()
try:
# Other code
except IntegrityError:
message = "Movie '{}' is already exists.".format(movie_name)
else:
message = "Please correct all the validation errors below."
#### Step 9: Implement Delete Confirm using GET and delete it in POST ####
## Lets use URL string instead of query string for remove
# Enhance the HTML
<li> <a href="/movie/remove/{{ movie.pk }}/"> [x] </a> {{ movie.name }} </li>
# Enhance the routing configuration (urls.py) to accomodate the same
url(r'^movie/remove/(?P<movie_id>\d+)/$', 'movie.views.remove_movie'),
# Create a new template for delete confirmation fav/movie/templates/movie_delete_confirm.html
<!DOCTYPE html>
<html>
<head>
<title>My Fav Movie List - Delete Confirmation</title>
</head>
<body>
<form method="post"> {% csrf_token %}
Would you like to delete the movie <b> '{{ movie.name }}' </b>?
<input type="submit" value="Yep. Sure!">
</form>
</body>
</html>
# Enhance the remove view for confirmation and delete using post
def remove_movie(request, movie_id):
if request.method == 'GET':
try:
movie = Movie.objects.get(id = movie_id)
return render(request,
"movie_delete_confirm.html",
{ 'movie' : movie})
except Movie.DoesNotExist as e:
message = "Given movie does not exists."
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies(),
"form" : MovieForm()})
if request.method == 'POST':
try:
movie = Movie.objects.get(id = movie_id)
movie.delete()
message = "Movie '{}' is removed successfully.".format(movie.name)
except Movie.DoesNotExist as e:
message = "Given movie does not exists."
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies(),
"form" : MovieForm()})
return ("Invalid Request")
#### Step 10: Implement Edit feature ####
# Add the Edit option the HTML (movies.html)
<li> <a href="/movie/remove/{{ movie.pk }}/"> [x] </a>
<a href="/movie/edit/{{ movie.pk }}/"> [Edit] </a>
{{ movie.name }}
</li>
# Add the routing for edit feature
url(r'^movie/edit/(?P<movie_id>\d+)/$', 'movie.views.edit_movie'),
# Create a new template for edit fav/movie/templates/edit.html
<!DOCTYPE html>
<html>
<head>
<title>My Fav Movie List - Edit</title>
</head>
<body>
{% if message %}
{{ message }} <br> <br>
{% endif %}
<form method="post"> {% csrf_token %}
{{ form }}
<input type="submit" value="Edit">
</form>
</body>
</html>
# Enhance the remove view for confirmation and delete using post
def edit_movie(request, movie_id):
if request.method == 'GET':
try:
movie = Movie.objects.get(id = movie_id)
form = MovieForm(initial = {'movie_name': movie.name })
return render(request,
"movie_edit.html",
{ 'form' : form})
except Movie.DoesNotExist as e:
message = "Given movie does not exists."
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies(),
"form" : MovieForm()})
if request.method == 'POST':
form = MovieForm(request.POST)
if form.is_valid():
movie_name = form.cleaned_data["movie_name"].strip()
try:
movie = Movie.objects.get(id = movie_id)
movie.name = movie_name
movie.save()
message = "Movie '{}' is successfully.".format(movie_name)
form = MovieForm()
except IntegrityError:
message = "Movie '{}' is already exists.".format(movie_name)
except Movie.DoesNotExist as e:
message = "Given movie does not exists."
else:
message = "Please correct all the validation errors below."
return render(request,
"movie_edit.html",
{ 'form' : form})
return render(request,
"movies.html",
{"message" : message,
"movies" : _get_movies(),
"form" : form})
return ("Invalid Request")
#### Step 11: Enable Django Admin for Movie Model ####
# Enhance the Django Form to use Django Model Form
from movie.models import Movie
class MovieForm(forms.ModelForm):
# movie_name = forms.CharField(required = True)
class Meta:
model = Movie
def clean_name(self):
movie_name = self.cleaned_data['name'].strip()
if len(movie_name) < 3:
raise forms.ValidationError("Not enough words!")
return movie_name
# Create a Admin class for Movie Model and register it (fav/movie/admin.py)
from movie.models import Movie
from movie.forms import MovieForm
class MovieAdmin(admin.ModelAdmin):
form = MovieForm
admin.site.register(Movie, MovieAdmin)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment