django

  • Overview
  • URLS  and Views
  • Templates
  • Models
  • Templates Revisited
  • Miscellaneous

Overview


  • Django is a framework designed to make common web development tasks fast and easy.
  • It follows the MVC architectural pattern

URLS and Views



Starting a project

  • Start a test project     
django-admin.py startproject test_project
cd test_project
python manage.py startapp test_app1 

URLS and VIEWS

  • Below is a sample url regex for home page view:
  • URLS:
        url(r'^test_app1/', include('test_project.test_app1.urls')),
    
    test_app1/URLS:
    
        url(r'^/?$', 'test_app1.views.home', name='home'),
    
  • Below is the controller view for home page :
  • from django.shortcuts import HttpResponse, render_to_response
    
    def home(request):
           return HttpResponse("Home Page!")
    #        return render_to_response('test_app1/home.html', {'developer_name':'vivek'})
    
    

TEMPLATES

  • Templates are the actual views in MVC framework.
  • A template is simply a text file
  • A template contains variables , which get replaced with values when the template is evaluated, and   tags  , which control the logic of the template
  • Any text surrounded by a pair of braces (e.g., {{ person_name }} ) is a   variable . This means “insert the value of the variable with the given name.”

  • Any text that’s surrounded by curly braces and percent signs (e.g., {% if is_experienced %} ) is a  template tag

Templates

  • Lets create a template for home page
  • mkdir -p templates/test_app1
    
    <html>
      <body>
         This page is developed by 
    {{ developer_name }}!
      </body>
    </html>
    
    
    

MODELS

  • A model is the single, definitive source of information about your data
  • It contains the essential fields and behaviors of the data you’re storing
  • Each model is a Python class that subclasses  django.db.models.Model.
  • Add DB credentials to settings.py
  • Create model
 class Developer(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=100)
        experience = models.IntegerField() 
python manage.py syncdbfrom test_app1 import modelsmodels.Developer(name='vivek', experience=3).save()


TEMPLATES REVISTED

  • Template inheritance
  • A website has many common features that spread across various pages or the whole website.
  • In-order to avoid template duplication, django provides the following template inheritance logic:
  • The first step is to define a  base template  – a skeleton of your page that  child templates  will later fill in.
  • <html lang="en">
     <head>
        <title>{% block title %}{% endblock %}</title>
     </head>
     <body>
        <h1>My first site</h1>
        {% block content %}{% endblock %}
        {% block footer %}
        <hr>
        <p>Thanks for visiting my site.</p>
        {% endblock %}
     </body>
    </html>    

    CHILD TEMPLATE

    {% extends "base.html" %}
    
    {% block title %}Home Page{% endblock %}
    
    {% block content %}
    <p>>This page is developed by {{ developer_name }}!</p>
    {% endblock %}
    
    INCLUDE TEMPLATES
    • This tag allows you to include the contents of another template.
    {% include "inclusions/disclaimer.html" %}
    • Inclusion Template:

     mkdir -p  templates/inclusions
    
    disclaimer.html:
        <p>&copy;Global Analytics</p>
    

    TEMPLATE TAGS

    • Add model logic to controller:
    • from django.shortcuts import HttpResponse, render_to_response
      from test_app1.models import Developer
      def home(request):
              developers = Developer.objects.all()
              return render_to_response('test_app1/home.html', {'developers':developers})
      
      
     <table>
    	<tr>
    		<th>Developer Name</th>
    		<th>Designation</th>
    	</tr>
    	 {% for developer in developers %}
    	<tr>
    		<td>{{ developer.name }}</td>
    		<td>
    			{% if developer.experience > 2 %}
    	    			Senior Developer
    			{% else %}
    	   			Developer
    			{% endif %}
    		</td>
    	</tr>
            {% endfor %}
    </table>
    <p>This page is developed by {{ developers.0.name }}!</p>
    
    
    • You can even create custom template tags

    Middlewares

      • On occasion, you’ll need to run a piece of code on each and every request that Django handles. This code might need to modify the request before the view handles it, it might need to log information about the request for debugging purposes, and so forth
      • Various django middlewares:
        • process_request() is called on each request, before Django decides which view to execute.
        • process_view() is called just before Django calls the view
        • process_template_response() is called before context from view is rendered on the template
        • process_response() is called on all responses before they’re returned to the browser.
        • process_exception is called on all exceptions raised from view. It wont be called when no exception is raised.
      • To activate a middleware component, add it to the MIDDLEWARE_CLASSES tuple in your settings module.
    • MIDDLEWARE_CLASSES = (
          'django.middleware.common.CommonMiddleware',
          'django.contrib.sessions.middleware.SessionMiddleware',
          'django.middleware.csrf.CsrfViewMiddleware',
          'django.contrib.auth.middleware.AuthenticationMiddleware',
          'django.contrib.messages.middleware.MessageMiddleware',
      )
      



    Middlewares

    • test_middleware.py:
    • import uuid
      class TestMiddleware(object):
          def process_request(self, request):
              unique_id = request.COOKIES.get(\
                 'unique_id', str(uuid.uuid4()))
              request.__setattr__('unique_id', unique_id)
      
      
    • views.py:
    •  return render_to_response('test_app1/home.html', \
      {'developers':developers, 'unique_id':request.unique_id})
      
    • home.html:
    •  <p>Your unique id is: {{ unique_id }}</p>

    Context Processors

  • Context processors allows us to add common variables to the context dictionary before getting passed to the template
  • create a context_processors.py file in the Django project folder:
  • def extra_context(request):
        """
        Add variables that you would like accessed across all pages.
        """
        context_extras = {}
        context_extras['unique_id'] = request.unique_id 
        return context_extras
    
    • And on the settings file under TEMPLATE_CONTEXT_PROCESSORS  added:
    'test_project.context_processors.extra_context'
    

    Views.py:
    from django.template import RequestContext
            return render_to_response('test_app1/home.html', {'developers':developers}, context_instance=RequestContext(request))

    Class Based Views

    from test_app1.views import AddDeveloper
    
        url(r'^add/?$', AddDeveloper.as_view(), name='add'),
    
    views:
    class AddDeveloper(View):
        def get(self, *args, **kwargs):
            return render_to_response('test_app1/add.html', {}, context_instance=RequestContext(self.request))
    
    
        def post(self, *args, **kwargs):
            print self.request.POST
            if self.is_valid():
                Developer(name=self.request.POST['developer_name'], experience=self.request.POST['experience']).save()
                return HttpResponseRedirect("/test_app1/")
            else:
                return render_to_response('test_app1/add.html', {'errors':self.errors}, context_instance=RequestContext(self.request))
    
    
        def is_valid(self):
                self.errors = {}
                if not self.request.POST.get('developer_name'):
                    self.errors['developer_name'] = 'Please enter developer name'
                if not self.request.POST.get('experience'):
                    self.errors['experience'] = 'Please select your experience'
                return False if self.errors else True
    
    

    Add developer Template

    <style>
    .error {    color: red;}
    </style><form method="post" >
        {% csrf_token %}
        <label>Dev Name</label>
        {% if errors.developer_name %}
            <span class="error">{{ errors.developer_name }}</span>
        {% endif %}    <input type="text" name="developer_name" />
        <br>
        <br>
        <label>Experience</label>
        {% if errors.experience %}
            <span class="error">{{ errors.experience }}</span>
        {% endif %} <select name="experience">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <input type="submit" value="submit" name="submit" />
    </form>

    Forms

    • Django provides a form library to avoid the previous issues
    • create forms.py inside the application
    • from django import forms
      EXPERIENCE = (
                      ('1','1',),
                      ('2','2',),
                      ('3','3',),
                   )
      class DeveloperForm(forms.Form):
         name = forms.CharField(required=True, label='Developer Name')
         experience = forms.ChoiceField(choices=EXPERIENCE, widget=forms.Select(attrs={'data-field': '1'}), required=True)
      
      
    • Now lets write the controller logic:
    • class AddDeveloper(View):
          def get(self, *args, **kwargs):
              form = DeveloperForm()
              return render_to_response('test_app1/add.html', {'form':form}, context_instance=RequestContext(self.request))
          def post(self, *args, **kwargs):
              form = DeveloperForm(self.request.POST)
              if form.is_valid():
                  Developer(name=self.request.POST['developer_name'], experience=self.request.POST['experience']).save()
                  return HttpResponseRedirect("/test_app1/")
              else:
                  return render_to_response('test_app1/add.html', {'form':form}, context_instance=RequestContext(self.request))
      
      
    • Now the template:
    <style>
    .error {
        color: red;
    }
    </style>
    <form method="post" >
        {% csrf_token %}
            <span class="error">{{form.name.errors.as_text }}</span><br/>
        {{ form.name.label }}
        {{ form.name }}
        <br>
        <br>
        {{ form.experience.label }}
        {{ form.experience }}
        <br>
        <br>
        <input type="submit" value="submit" name="submit" />
    </form>
    
    
    • You can also add custom validations
       def clean_name(self):
            name = self.cleaned_data['name']
            num_words = len(name.split())
            if num_words < 2:
                raise forms.ValidationError("Enter first & last name")
            return name
    

     

    Do's & Dont's

    • Do not write all patterns in main urls
    • Do not write the whole logic in your views
    • Try using class based views
    • Always catch exceptions
    • # BAD!
      def ua_display_bad(request):
          ua = request.META['HTTP_USER_AGENT']  # Might raise KeyError!
          return HttpResponse("Your browser is %s" % ua)
      
      # GOOD (VERSION 1)
      def ua_display_good1(request):
      
      #OR ua = request.META.get('HTTP_USER_AGENT', 'unknown')
      try: ua = request.META['HTTP_USER_AGENT'] except KeyError: ua = 'unknown' return HttpResponse("Your browser is %s" % ua)
    • Explore more on generic CBV's, custom template tags, model managers, mixins & forms

    Django Basics

    By vivek soundrapandi

    Django Basics

    A practical session on django with basics to advanced concepts

    • 4,883