»
S
I
D
E
B
A
R
«
Evejob Sprint #1 Domain Model Part #2: EvejobDJ Django Models
Nov 10th, 2009 by evereq

OK, in Part #1 we already figure out what Models we need to create. Because Django support concept of “applications” inside one project, we can actually start creating models for 3 applications:

  • Accounts (User profiles, registration, authentication / authorization etc)
  • Companies (Companies catalog, profiles etc)
  • Common (seems City and Country are good example of entities that will be used in other applications)

Django internally support following concepts that will be used in Accounts application:

  1. Users
  2. Groups (known in other frameworks as “User Roles”)
  3. User Profile (you need to create your own model for it, but Django have special support for this)
So, Let’s create “accounts” Django Application that will dial with Users Registration, Login, Logout, Profiles etc
cd c:\evejob\EvejobDJ
python manage.py startapp accounts

The same way, you can create now “common” and “companies” applications in EvejobDJ project.

Let’s take a look into possible simple “accounts” application model.py file:

from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
 
class UserProfile(models.Model):
 
    # required field - user that own profile
    user = models.ForeignKey(User, unique=True)
 
    # optional Job Title
    job_title = models.CharField(_("Job Title"), max_length=128, null = True, blank = True)
 
    # optional Phone Number
    phone = models.CharField(_("Phone"), max_length=16, null = True, blank = True)
 
    # Boolean stored as tinyint in MySQL database, but it's ok for now
    allow_site_to_contact_by_email = models.BooleanField(_("Allow site to contact me by email"))
    allow_site_partners_to_contact_by_email = models.BooleanField(_("Allow site partners to contact me by email"))
    allow_site_to_contact_by_phone = models.BooleanField(_("Allow site to contact me by phone"))
    allow_site_partners_to_contact_by_phone = models.BooleanField(_("Allow site partners to contact me by phone"))
 
    def __unicode__(self):
       return self.user.username

Let’s review now most important aspects of this code:

from django.contrib.auth.models import User

Line above import already defined in Django User Model. We not going to create our own User Model and will try to reuse as much as possible from what is available in Django framework. But because we need to hold additional user details (like job title or phone for example), we create “UserProfile” model, that reference User as Foreign Key:

# required field - user that own profile
user = models.ForeignKey(User, unique=True)

Also we are going to use “Internationalization” (I18N) build in into Django functionality to made our site available in few languages:

from django.utils.translation import ugettext_lazy as _

After such import, to translate string from one language into another we need just use _(”String to translate”) pattern (sure and also define translations some way – more about it in dedicated article)

Other code just define different fields of UserProfile that we want actually to store in Database (some of them are strings, some booleans).

Last two lines used to get a “string” representation of the model that will be used in Django Admin for example (same idea like you can “override ToString()” in C#):

    def __unicode__(self):
       return self.user

That’s it for accounts application regarding models!

For “common” application we will have to define two model classes (City and Country):

from django.db import models
from django.contrib.auth.models import User
import EvejobDJ.settings as settings
from django.utils.translation import ugettext_lazy as _
 
class Country(models.Model):
 
    # required Unique Company Name
    name = models.CharField(_("Name"), max_length=255, unique = True)
 
    def __unicode__(self):
       return '%s' % (self.name)
 
    class Meta:
       verbose_name = _('Country')
       verbose_name_plural = _('Countries')
 
class City(models.Model):
 
    # required Unique Company Name
    name = models.CharField(_("Name"), max_length=255, unique = True)
 
    country = models.ForeignKey(Country, unique = False)
 
    def __unicode__(self):
       return '%s' % (self.name)
 
    class Meta:
       verbose_name = _('City')
       verbose_name_plural = _('Cities')

Exactly same logic like for Profiles, with small addition to made correct “plural” name for entity using definitions for “verbose_name_plural” field on Meta class. This will allow to see “Cities” or “Countries” in Admin, instead of automatic “Citys” or “Countrys” :)

    class Meta:
       verbose_name = _('City')
       verbose_name_plural = _('Cities')

And last models that we need to produce in Sprint #1 is for Companies – Company and CompanyLogo.
Let’s review following code:

from django.db import models
from django.contrib.auth.models import User
import EvejobDJ.settings as settings
from django.utils.translation import ugettext_lazy as _
 
class Company(models.Model):
 
    # required Unique Company Name
    name = models.CharField(_("Name"), max_length=255, unique = True)
 
    # user that create this company first time.
    creation_by = models.ForeignKey(User, unique = False)
 
    # when user create this company first time. Django Automatically set the field to now when Company created for the first time
    creation_date = models.DateTimeField(_("Create Date"), auto_now_add = True)
 
    city = models.ForeignKey('common.City', unique = False, null = True, blank = True)
    country = models.ForeignKey('common.Country', unique = False, null = True, blank = True)
 
    # logo = models.OneToOneField('CompanyLogo', related_name='logo', verbose_name = "company logo")
    # But this is not needed, as you always can get access to logo using something like
    # (read more http://docs.djangoproject.com/en/dev/topics/db/queries/#one-to-one-relationships)
    # e = Company.objects.get(id=2)
    # e.companylogo
 
    def __unicode__(self):
       return '%s' % (self.name)
 
    class Meta:
       verbose_name = _('Company')
       verbose_name_plural = _('Companies')
 
class CompanyLogo(models.Model):
 
    company = models.OneToOneField(Company, primary_key=True)
 
    # user that create this logo first time.
    creation_by = models.ForeignKey(User, unique = False)
 
    # when user create this logo first time. Django Automatically set the field to now when logo created for the first time
    creation_date = models.DateTimeField(_("Create Date"), auto_now_add = True)
 
    caption = models.CharField(blank=True, null = True, max_length=100)
 
    image = models.ImageField(upload_to=settings.COMPANY_LOGO_RELATIVE_ROOT)
 
    def __unicode__(self):
       return '%s' % (self.company.name)
 
    class Meta:
       verbose_name = _('Company Logo')
       verbose_name_plural = _('Companies Logos')

Let’s take a look into some interesting things here… First of all, we will store currently company logo images in file system (but later we can use another storage provider). Thanks to Django, it have special field type for this: “ImageField”. Ones we add field with this type, we need to make sure that we install PIL library. You can read about some installation issues of it on dedicated post). Second take a look into “auto_now_add” parameter in creation_date field – this will instruct Django to automatically set the field to current date when user create new company logo! And last most important thing in this models is One To One relation (using models.OneToOneField) between CompanyLogo and Company entities! You can read more information about Django support of “One To One” relations” if you interesting in details.

That’s all regarding Models itself. Let me know if have any questions!

Notes:
To run code that you see above (at least to be able to create database using ‘python manage.py syncdb’ command), you need to made some settings in settings.py file. At minimum you need to add “accounts”, “companies” and “common” into Django Applications list:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.flatpages',
    'common',
    'accounts',
    'companies',
)

Also you probably need to define some settings like COMPANY_LOGO_RELATIVE_ROOT in same settings.py file.
In any case, I recommend to wait a little and read next post to get more information how to actually run EvejobDJ models and create views!
So keep reading!
;)

P.S. And last thing: I want to let you know that Python is NOT my “primary language of choice”. Means that I DON’T do everyday coding on it (instead of C# for example), so if you see (and feel) that I do something wrong, or that it can be done in Python better please let me know!

Evejob Project Management Part #3: Sprint #1. Employer Users, Registration, Profile
Nov 6th, 2009 by evereq

The goal of Spring #1 is to made Registration and Profile for “Employer Users”. Sure “Employer Users” is just a “role” of some users that give such users ability to manage Companies and made Job Posts (instead of Job Candidates users, such users cannot manage resumes for example etc).

Some use cases that we need to implement in this sprint:

  1. As a Anonymous User I want to be able to see “Employer User Registration Page” so I could Register and enter my basic personal information including selecting of Company which I represent if it exists
  2. As a Registered User I want to be able to see  “Employer User Public Profile Page” for any Employer User so that I could review his personal information and if this user own Companies also his Companies list with company name and logo.
  3. As a Employer User I want to see “Edit Profile Page” so that I could edit my personal information.

Some screenshots that I draw in Microsoft Expression Blend 3 as SketchFlow Prototype:

CommonUserRegistration

EmployerUserRegistration

… work in progress under this post …

Evejob Project Management Part #1: Initial considerations
Nov 6th, 2009 by evereq

OK, now it is time to go deeply into business domain of Evejob – Social Job Board and made small Agile project management.

What we know about Job Boards in general:

  • Company (managed by Employer User) seek for Job Candidates that can fit to some available positions by review / search Job Candidates profiles and / or resumes.
  • Job Candidates Users / Anonymous Users seek (search) opened Job Positions published by Companies (Employers Users) – i.e. review Companies profiles / Job Posts and contact Companies / apply to available positions.

This is “base, common, required” functionality that looks like MUST be present (with some adjustments)  in any Job board so both Companies and Job Candidates found board useful!

Despite the fact that I have very important extension to such “base” functionality which will made Evejob project Unique and more “Social”, I still understand that base functionality must be done before… In any case, I will need to use such business domain entities, like “Company”, “Job Candidate”, “Job Post” etc.  So instead of spend my time now describing what made “Evejob” really unique let’s just start “base” implementation and move forward…

But how to start?! This is most problematic question… Do I need to made “big design upfront” or? Do I need to describe all use cases (made 100s  screenshots etc) or I need to start coding right now etc? In general answer as always: “it depends!”.  But in my case, I can simply start from small and using iterative approach continue development… But anyway, at least small plan will help me to be on track and help readers to understand what will be in next iterations.

So here is the plan that I take from project backlog for Release #1 (at least like I see it right now… I did not want to put here full project backlog for some trivial reasons…):

Release #1. Base Job Board

  • Sprint #1. Employer Users: Registration, Profile
  • Sprint #2. Employer Users: Manage Companies
  • Sprint #3. Employer Users: Manage Job Posts
  • Sprint #4. Employer Users: Dashboard
  • Sprint #5: Job Candidates: Registration, Profile
  • Sprint #6: Job Candidates: Resume Management
  • Sprint #7: Job Candidates: Dashboard

You can ask: why this specific order??? Why I am going to build for example Employer stuff before Job Candidates? Answer – from business point of view! Our goal to build software that can be used even after just few iterations, so what sense if for example I will made first Job Candidates resume management and made release of this? Who can use this? Nobody – it will be just catalog of Job Candidates resumes… Nobody will want to register, nobody will add own resume if he will understand that nobody will search for it as search still does not implemented on site!

But look at order that I select: if we implement first Companies catalog, then we can made release, even put application to hosting servers and  start fill it with local or even worldwide companies –  start to promote site to such companies, let them send us description information, add this information to our database… etc… Maybe even made some “special” pages for huge companies like Google or Microsoft ;-) And while we will made next X iterations, we will simultaneously improve our companies catalog, extend our public relations  and promote our business! Here we follow principle: “Release Early” (feel free to overview also other important principles that I follow in my projects). Also it is very important that doing such “early” release we will start getting feedback and start to dial with real production environment! It is specially important in cases, where you plan to host your application in “special” environments - Azure, Google App Engine are some examples of such environments – you simply don’t have full control, so as early you start, as much “problems” you will face and fix in initial steps!

I put Sprint #1 – Sprint #7 into “Release #1″ because I think (at least now) that we can call “Evejob” project “version 1″ only after Spring #1 – Sprint #7 will be done and not before as all this functionality required for any job board application! As I tell before – it does not mean that I will put site into production only after complete all 7 sprints – I will be Agile and at least for now I see that it make sense to put site into production right after sprint #2…

For those who want to know little more, I will put here overview for next few releases:

Release #2. Following

This what will made site unique – “Follow” principle, something like Twitter but for Job Boards ;-) Want to know more – just stay with me ;-)

Release #3. Search

This release will be dedicated to different simple and advanced search features.

In next posts I will go deeply into each sprint, so stay tuned!

»  Substance: WordPress   »  Style: Ahren Ahimsa
© Copyright 2008–2009 EvereQ.com All rights reserved.