Sri Sai Vidya Vikas Shikshana Samithi ®
SAI VIDYA INSTITUTE OF TECHNOLOGY
Approved by AICTE, New Delhi, Affiliated to VTU, Recognized by Govt. of Karnataka
Accredited by NBA
RAJANUKUNTE, BENGALURU 560 064, KARNATAKA
Phone: 080-28468191/96/97/98 ,Email:
[email protected], URLwww.saividya.ac.in
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING (CSE)
Module-3:
Chapter 1: Django Admin Interfaces and Model Forms
Introduction:
The admin interface is a crucial part of many websites, allowing trusted administrators to manage site content
through a web-based platform. Examples include blog posting interfaces, comment moderation tools, and content
management systems for updating site information.
However, building admin interfaces is often seen as tedious and repetitive. Tasks like user authentication, form
handling, and input validation are necessary but monotonous aspects of web development.
Django addresses this issue by automating the creation of admin interfaces. With Django, you can set up a fully
functional admin interface with minimal code. This automation leverages the metadata in your models to create a
comprehensive and ready-to-use admin panel.
This chapter explores Django's automatic admin interface, detailing how to activate, use, and customize it to fit
specific needs. With Django's approach, developers can quickly implement robust admin interfaces without the usual
repetitive work.
3.1 Activating the Admin Interface
Activating Django's admin interface involves three steps:
1. Add admin metadata to models: Mark models that should have an admin interface by adding an inner
Admin class.
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
class Admin:
pass
2. Install the admin application: Add django.contrib.admin to INSTALLED_APPS in your settings and run python
manage.py syncdb to set up the necessary database tables. If you didn't create a superuser previously, run
django/contrib/auth/bin/create_superuser.py.
3. Add the admin URL pattern: Ensure your urls.py includes the admin URL pattern.
Dept. of CSE, SVIT Page 1
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^admin/', include('django.contrib.admin.urls')),
)
Finally, run the development server with python manage.py runserver and access the admin interface at
http://127.0.0.1:8000/admin/. Log in and explore the admin functionalities.
3.2 Using the Admin Interface
The Django admin interface is designed to be user-friendly, even for nontechnical users.
Steps to how to use them:
1. Logging In
The admin interface starts with a login screen where you use your superuser credentials.
2. Main Index Page
After logging in, you’ll see the main index page, listing all objects with an Admin declaration.
You can manage users, groups, and permissions from this page.
3. Change Lists and Edit Forms
Change Lists: These are index pages for objects, showing a list of entries. You can customize which fields appear
and add features like search fields and filters.
Edit Forms: Used to create and modify objects, these forms show fields defined in your model with appropriate
widgets for each field type (e.g., date pickers for date fields).
4. Input Validation
The admin interface includes input validation, highlighting errors if required fields are left blank or invalid data is
entered.
5. Object History
Each object has a History button to view a log of changes made through the admin interface.
6. Deletion Confirmation
Deleting an object requires confirmation. The interface shows all related objects that will also be deleted to
prevent accidental data loss.
Managing Users, Groups, and Permissions
User Management: Users can be created, edited, and deleted through the admin interface. User objects include
fields for username, password, email, and real name.
User Permissions: Users have three flags:
o is active: Controls if the user can access any login-required URLs.
o is staff: Allows the user to log in to the admin interface.
Dept. of CSE, SVIT Page 2
o is superuser: Grants full access to all admin features, bypassing regular permissions.
Permissions: Each model has create, edit, and delete permissions. These are used to control what actions users
can perform.
Groups: Users can be assigned to groups, which are sets of permissions applied to all members. Groups make it
easy to manage permissions for many users at once.
3.3 Customizing the Admin Interface
Customizing the Django admin interface involves:
Enhancing model admin declarations to improve data management.
Using Django's template system to change the look and feel of the admin pages.
Modifying the admin index page to prioritize important applications and improve navigation.
These customizations, achieved with minimal code, significantly improve the admin interface's functionality and user
experience.
1. Enhancing the Book Model's Admin Interface:
By default, the Django admin change list shows only the string representation of each model. To improve usability,
especially with large datasets, you can customize the display, search, and filtering options.
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
class Admin:
list_display = ('title', 'publisher', 'publication_date')
list_filter = ('publisher', 'publication_date')
ordering = ('-publication_date',)
search_fields = ('title',)
list_display: Specifies the columns displayed in the change list.
list_filter: Adds a filter sidebar for specified fields.
ordering: Orders the list by specified fields.
search_fields: Adds a search box for specified fields.
These changes enhance the usability of the admin interface, making it easier to locate and manage entries.
Dept. of CSE, SVIT Page 3
2. Customizing the Admin Interface’s Look and Feel
To change the appearance of the admin interface, use Django's template system:
Edit the Site Header:
Locate the default admin/base_site.html template in django/contrib/admin/templates.
Copy it to your custom template directory (e.g., /home/mytemplates/admin/base_site.html).
Modify the copied template to replace "Django administration" with your site's name.
Override Other Admin Templates:
Any default admin template can be overridden similarly by copying it to your custom directory and editing it.
3. Custom Admin Index Page:
Copy admin/index.html to your custom template directory.
Edit it to reorder applications or add custom content.
Use {% get_admin_app_list as app_list %} to retrieve installed applications or hard-code links as needed.
For an automated approach, run python manage.py adminindex <app> to generate template code for
inclusion in the index template.
3.4 Reasons to use Admin Interfaces
1. Data Entry:
Primary Use: The admin interface is ideal for any data entry tasks, especially when nontechnical users
need to enter data. It allows content producers to input data while developers focus on building the
public-facing interface.
Example: At a newspaper, a reporter enters data about a special report through the admin interface while
developers work on the feature’s frontend.
2. Inspecting Data Models:
o Initial Testing: When a new model is defined, developers use the admin interface to enter dummy data.
This helps quickly identify and correct data modeling mistakes by providing a graphical representation of
the model.
3. Managing Acquired Data:
o Data Corrections: For sites that acquire data automatically (e.g., through scraping or APIs), the admin
interface is useful for manually editing and correcting any issues that arise with the acquired data.
o Example: A site like chicagocrime.org, which collects data automatically, can use the admin interface to
correct errors in the acquired data.
Benefits:
Ease of Use: The admin interface is designed for nontechnical users, making it easy for content producers to
manage data without needing technical skills.
Efficiency: By enabling simultaneous work of content producers and developers, the admin interface streamlines
the development process.
Dept. of CSE, SVIT Page 4
Flexibility: The interface is not just for data entry but also for inspecting and managing data, providing a versatile
tool for various backend tasks.
Dept. of CSE, SVIT Page 5
Chapter-4: Form Processing
4.1 Form processing
Form processing refers to the series of steps taken to handle and validate user input submitted through HTML forms in a
web application. In Django, form processing typically involves the following steps:
1. Display the Form:
o The form is presented to the user, allowing them to input data. This can be an initial empty form or a form
pre-filled with existing data.
2. Receive the Input:
o When the user submits the form, the input data is sent to the server, typically via a POST request, though
GET requests can also be used for forms like search.
3. Validate the Input:
o The server checks the submitted data against the validation rules defined for the form fields. This includes
checking required fields, data types, value ranges, and any custom validation rules.
4. Handle Valid Data:
o If the form data is valid, it is processed. This might involve saving the data to a database, sending an email,
or performing other actions depending on the form’s purpose.
5. Handle Invalid Data:
o If the form data is invalid, the form is re-rendered with error messages and the user’s input, allowing the
user to correct their mistakes without having to re-enter all the data.
6. Render a Response:
o After processing the form, the server sends a response back to the client. This could be a new page, a
confirmation message, or a re-rendered form with error messages.
4.2 Creating a Feedback Form
Creating a feedback form in Django involves several steps, from defining the form fields and validation rules to processing
the form data and displaying appropriate error messages
The process of building a simple feedback form using Django’s forms framework.
Step 1: Defining the Form
Start by creating a new file called forms.py in your Django application directory. Define the form fields using Django’s form
classes.
# forms.py
from django import forms
TOPIC_CHOICES = (
('general', 'General enquiry'),
('bug', 'Bug report'),
Dept. of CSE, SVIT Page 6
('suggestion', 'Suggestion'),
)
class ContactForm(forms.Form):
topic = forms.ChoiceField(choices=TOPIC_CHOICES)
message = forms.CharField(widget=forms.Textarea())
sender = forms.EmailField(required=False)
topic: A choice field where users can select the type of feedback.
message: A text field for the feedback message, using a TextArea widget to allow multiline input.
sender: An optional email field for users to provide their email address.
Step 2: Creating the View
Next, create or update a view function in your views.py to handle displaying and processing the form.
# views.py
from django.shortcuts import render, redirect
from .forms import ContactForm
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Process the data in form.cleaned_data
topic = form.cleaned_data['topic']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
# Implement your data handling logic here
# For example, save the feedback to the database or send an email
return redirect('success') # Redirect to a success page
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})
GET Request: When the page is initially loaded, an empty form is created.
POST Request: When the form is submitted, the data is validated. If valid, the form data is processed (e.g., saved to
the database or sent as an email).
Step 3: Creating the Template
Create a template named contact.html to render the form and handle user input.
<!-- contact.html -->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Contact Us</title>
</head>
<body>
Dept. of CSE, SVIT Page 7
<h1>Contact Us</h1>
<form method="POST">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
{{ form.as_table }}: Renders the form fields as a table. Other methods like as_ul and as_p can be used to render
fields as unordered lists or paragraphs.
Step 4: Handling Form Validation and Displaying Errors
When the form is submitted, any validation errors will be automatically displayed by the form framework. For example, if
the message field is left blank or an invalid email address is provided, the form will be re-rendered with appropriate error
messages.
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Process form data
topic = form.cleaned_data['topic']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
# Process the data
return redirect('success')
else:
# Form has errors
return render(request, 'contact.html', {'form': form})
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})
If the form is invalid, it is re-rendered with error messages automatically provided by Django.
4.3 Form submissions
When a user fills out a form and it passes validation, we often want to perform some action with the data. In the below
example, steps to send an email with the user's feedback using Django's email package is demonstrated
Steps:
1. Validate the Form Data
First, check if the form data is valid using the is_valid() method. If the form is valid, access the cleaned data.
form = ContactForm(request.POST)
if form.is_valid():
# Access the cleaned data
topic = form.cleaned_data['topic']
Dept. of CSE, SVIT Page 8
message = form.cleaned_data['message']
sender = form.cleaned_data.get('sender', '[email protected]')
2. Send the Email
Use Django's send_mail function to send the feedback via email. This function requires the subject, message body,
sender's email, and a list of recipient emails.
from django.core.mail import send_mail
send_mail(
'Feedback from your site, topic: %s' % topic,
message,
sender,
['[email protected]']
)
3. Redirect to a Confirmation Page
After sending the email, redirect the user to a confirmation page to inform them that their feedback has been
submitted successfully.
from django.http import HttpResponseRedirect
from django.shortcuts import render
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
topic = form.cleaned_data['topic']
message = form.cleaned_data['message']
sender = form.cleaned_data.get('sender', '[email protected]')
send_mail(
'Feedback from your site, topic: %s' % topic,
message,
sender,
['[email protected]']
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})
Complete View Function
Here's the complete implementation of the contact form view:
# views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.core.mail import send_mail
from .forms import ContactForm
def contact(request):
if request.method == 'POST':
Dept. of CSE, SVIT Page 9
form = ContactForm(request.POST)
if form.is_valid():
topic = form.cleaned_data['topic']
message = form.cleaned_data['message']
sender = form.cleaned_data.get('sender', '[email protected]')
send_mail(
'Feedback from your site, topic: %s' % topic,
message,
sender,
['[email protected]']
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})
Template for Contact Form
Here’s an example of a simple template for the contact form:
<!-- templates/contact.html -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>Contact Us</title>
</head>
<body>
<h1>Contact Us</h1>
<form action="." method="POST">
<table>
{{ form.as_table }}
</table>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html
4.4 Custom Validation
Objective: Ensure the feedback message contains at least four words.
Implementation: Add a clean_message method to the ContactForm class to validate the word count.
class ContactForm(forms.Form):
topic = forms.ChoiceField(choices=TOPIC_CHOICES)
message = forms.CharField(widget=forms.Textarea())
sender = forms.EmailField(required=False)
def clean_message(self):
message = self.cleaned_data.get('message', '')
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
Dept. of CSE, SVIT Page 10
CSS Styling for Error Messages:
Objective: Enhance the visual appearance of error messages.
CSS
<style type="text/css">
ul.errorlist {
margin: 0;
padding: 0;
}
.errorlist li {
background-color: red;
color: white;
display: block;
font-size: 10px;
margin: 0 0 3px;
padding: 4px 5px;
}
</style>
Custom HTML Template:
Objective: Customize form presentation and error display.
Template:
<form action="." method="POST">
<div class="fieldWrapper">
{{ form.topic.errors }}
<label for="id_topic">Kind of feedback:</label>
{{ form.topic }}
</div>
<div class="fieldWrapper{% if form.message.errors %} errors{% endif %}">
{% if form.message.errors %}
<ol>
{% for error in form.message.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
<label for="id_message">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="id_sender">Your email (optional):</label>
{{ form.sender }}
</div>
<p><input type="submit" value="Submit"></p>
</form>
4.5 Creating Forms from Models
DRY Principle:
Dept. of CSE, SVIT Page 11
Avoid repeating information across your application.
Ensure each piece of knowledge has a single, authoritative representation.
Publisher Form:
Instead of manually defining the form fields for the Publisher model, use form_for_model() to automatically
generate the form.
Example:
from models import Publisher
from django.newforms import form_for_model
PublisherForm = form_for_model(Publisher)
View for Adding Publisher:
Handle form submission and saving of a new Publisher instance.
Example:
def add_publisher(request):
if request.method == 'POST':
form = PublisherForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/add_publisher/thanks/')
else:
form = PublisherForm()
return render_to_response('add_publisher.html', {'form': form})
Auto-generated Form:
The form_for_model() creates a form class based on the Publisher model, including a convenient save() method.
form_for_instance() can be used to create preinitialized forms for editing existing model instances.
4.6 URLConf Ticks
In Django, URLconfs are simply Python code, which allows for various methods to streamline and optimize them as your
application grows in complexity.
1. Direct Import of View Functions
Initially, you might import view functions directly:
from django.conf.urls.defaults import *
from mysite.views import current_datetime, hours_ahead, hours_behind, now_in_chicago, now_in_london
urlpatterns = patterns('',
(r'^now/$', current_datetime),
(r'^now/plus(\d{1,2})hours/$', hours_ahead),
(r'^now/minus(\d{1,2})hours/$', hours_behind),
(r'^now/in_chicago/$', now_in_chicago),
Dept. of CSE, SVIT Page 12
(r'^now/in_london/$', now_in_london),
)
2. Importing the Entire Views Module
To reduce the number of import statements and streamline the URLconf, you can import the entire views module:
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^now/$', views.current_datetime),
(r'^now/plus(\d{1,2})hours/$', views.hours_ahead),
(r'^now/minus(\d{1,2})hours/$', views.hours_behind),
(r'^now/in_chicago/$', views.now_in_chicago),
(r'^now/in_london/$', views.now_in_london),
)
3. Using String References to View Functions
Django allows specifying view functions as strings, which can further simplify your URLconf:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^now/$', 'mysite.views.current_datetime'),
(r'^now/plus(\d{1,2})hours/$', 'mysite.views.hours_ahead'),
(r'^now/minus(\d{1,2})hours/$', 'mysite.views.hours_behind'),
(r'^now/in_chicago/$', 'mysite.views.now_in_chicago'),
(r'^now/in_london/$', 'mysite.views.now_in_london'),
)
4. Factoring Out a Common View Prefix
If your view function strings share a common prefix, you can factor it out to make the URLconf cleaner:
from django.conf.urls.defaults import *
urlpatterns = patterns('mysite.views',
(r'^now/$', 'current_datetime'),
(r'^now/plus(\d{1,2})hours/$', 'hours_ahead'),
(r'^now/minus(\d{1,2})hours/$', 'hours_behind'),
(r'^now/in_chicago/$', 'now_in_chicago'),
(r'^now/in_london/$', 'now_in_london'),
)
Advantages and Disadvantages
Both the string approach and the function object approach have their advantages:
String Approach:
o More compact and does not require importing view functions.
o More readable and manageable if view functions are spread across multiple modules.
Function Object Approach:
o Allows easy wrapping of view functions.
o More in line with Python traditions (passing functions as objects).
Dept. of CSE, SVIT Page 13
You can mix both approaches in the same URLconf depending on your needs.
4.6.1 Using Multiple View Prefixes
For URLconfs with views from multiple modules, you can combine multiple patterns() objects:
from django.conf.urls.defaults import *
urlpatterns = patterns('mysite.views',
(r'^/?$', 'archive_index'),
(r'^(\d{4})/([a-z]{3})/$', 'archive_month'),
)
urlpatterns += patterns('weblog.views',
(r'^tag/(\w+)/$', 'tag'),
)
4.6.2 Dynamic URLconf Behavior in Debug Mode
You can dynamically alter URLconf behavior based on the DEBUG setting:
from django.conf.urls.defaults import *
from django.conf import settings
urlpatterns = patterns('',
(r'^$', 'mysite.views.homepage'),
(r'^(\d{4})/([a-z]{3})/$', 'mysite.views.archive_month'),
)
if settings.DEBUG:
urlpatterns += patterns('', (r'^debuginfo$', 'mysite.views.debug'))
4.6.3 Using Named Groups in URLs
Named groups in regular expressions can make your URLconf more explicit and less error-prone:
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^articles/(?P<year>\d{4})/$', views.year_archive),
(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),
)
This approach ensures that the captured values are passed to the view as keyword arguments:
def month_archive(request, year='2006', month='03'):
# ...
4.6.4 Capturing Text in URLs
Remember that captured values are passed as strings, so you may need to convert them:
from django.conf.urls.defaults import *
import datetime
Dept. of CSE, SVIT Page 14
urlpatterns = patterns('',
(r'^articles/(\d{4})/(\d{2})/(\d{2})/$', views.day_archive),
)
def day_archive(request, year, month, day):
date = datetime.date(int(year), int(month), int(day))
# ...
4.6.5 Passing Extra Options to View Functions
You can pass additional information to views via URLconf parameters:
# urls.py
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}),
(r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),
)
# views.py
from django.shortcuts import render_to_response
def foobar_view(request, template_name):
m_list = MyModel.objects.filter(is_new=True)
return render_to_response(template_name, {'m_list': m_list})
4.7 Including Other URLconfs
In Django, URLconfs can be organized using the include() function to manage URLs across different applications or
modules. Here’s a summary of key points regarding the use of include() in URLconfs:
1. Purpose of include():
o Allows inclusion of other URLconfs into the current URLconf, effectively "nesting" URLs.
o Simplifies URL management by breaking down large URLconfs into smaller, reusable components.
2. Basic Usage:
o Syntax: include(module_or_pattern_list, namespace=None, app_name=None)
o Example: include('myapp.urls')
3. Behavior:
o When Django encounters include(), it removes the part of the URL that matched up to that point and
passes the remaining string to the included URLconf for further processing.
o Useful for structuring URLs hierarchically and separating concerns between different parts of an
application.
4. Captured Parameters:
o Parameters captured in the parent URLconf are passed down to the included URLconf.
o Example: r'^(?P<username>\w+)/blog/' include('foo.urls.blog')
o Ensures captured parameters are available to all views within the included URLconf.
5. Extra Options:
Dept. of CSE, SVIT Page 15
o Additional options (as a dictionary) can be passed to include() to be applied to every line in the included
URLconf.
o Example: include('inner', {'blogid': 3})
o Options are passed regardless of whether individual views in the included URLconf use them, so caution is
advised.
6. Best Practices:
o Organize URLconfs logically to maintain clarity and separation of concerns.
o Use include() for modularization and reusability, especially in large projects or across multiple applications.
o Ensure consistency in parameter passing and option usage across included URLconfs to avoid unexpected
behavior.
By leveraging include() effectively, Django developers can create scalable and maintainable URL structures that enhance
the overall organization of their web applications.
Dept. of CSE, SVIT Page 16