FSD Module 3 Notes
FSD Module 3 Notes
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.
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.
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.
The Django admin interface is designed to be user-friendly, even for nontechnical users.
1. Logging In
The admin interface starts with a login screen where you use your superuser credentials.
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.
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.
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.
These customizations, achieved with minimal code, significantly improve the admin interface's functionality and user
experience.
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',)
These changes enhance the usability of the admin interface, making it easier to locate and manage entries.
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.
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:
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.
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'),
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.
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']
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).
Create a template named contact.html to render the form and handle user input.
{{ 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.
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']
If the form is invalid, it is re-rendered with error messages automatically provided by Django.
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:
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]')
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.
send_mail(
'Feedback from your site, topic: %s' % topic,
message,
sender,
['[email protected]']
)
After sending the email, redirect the user to a confirmation page to inform them that their feedback has been
submitted successfully.
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()
# 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()
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
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>
Template:
DRY Principle:
Publisher Form:
Instead of manually defining the form fields for the Publisher model, use form_for_model() to automatically
generate the form.
Example:
PublisherForm = form_for_model(Publisher)
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.
In Django, URLconfs are simply Python code, which allows for various methods to streamline and optimize them as your
application grows in complexity.
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),
To reduce the number of import statements and streamline the URLconf, you can import the entire views module:
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),
)
Django allows specifying view functions as strings, which can further simplify your URLconf:
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'),
)
If your view function strings share a common prefix, you can factor it out to make the URLconf cleaner:
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'),
)
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.
For URLconfs with views from multiple modules, you can combine multiple patterns() objects:
urlpatterns = patterns('mysite.views',
(r'^/?$', 'archive_index'),
(r'^(\d{4})/([a-z]{3})/$', 'archive_month'),
)
urlpatterns += patterns('weblog.views',
(r'^tag/(\w+)/$', 'tag'),
)
You can dynamically alter URLconf behavior based on the DEBUG setting:
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'))
Named groups in regular expressions can make your URLconf more explicit and less error-prone:
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:
Remember that captured values are passed as strings, so you may need to convert them:
# 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
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:
By leveraging include() effectively, Django developers can create scalable and maintainable URL structures that enhance
the overall organization of their web applications.