This course will become read-only in the near future. Tell us at community.p2pu.org if that is a problem.

Syncing our database and trying out the built in admin


Below you will find the models that I've created for this project. I recommend that you all use the same models as me to make it easier for troubleshooting. 

By now you should have created an app in your project folder (I created 2) and attempted to model the database we will need based on the requirements listed in the last task. See my models below that is a good starting point. I've tried to comment in them to explain what's going on. If you have a question let me know. 

 

# recipe/models.py
 
from django.db import models
from django.contrib.auth.models import User
 
# python module for dates and time
import datetime
 
class FoodType(models.Model):
    # always set a character length
    # blank = False and null = False make the field required
    name = models.CharField(max_length = 100, blank = False, null = False)
    
    def __unicode__(self):
        return '%s' % self.name
 
class Recipe(models.Model):
    title = models.CharField(max_length = 100, blank = False, null = False)
    # this is a many to many since a dish can have more than one food type
    food_type = models.ManyToManyField(FoodType)
    added_by = models.ForeignKey(User)
    # this tells the model to automatically timestamp it when it is added
    date_added = models.DateField(auto_now_add=True, default=datetime.datetime.now)
    instructions = models.TextField(max_length = 2000, blank = False, null = False)
    ingredients = models.TextField(max_length = 1000)
    
    def __unicode__(self):
        return '%s' % self.title
 
-------------------
 
# account/models.py
from django.db import models
from django.contrib.auth.models import User
 
from recipe.models import FoodType
 
# Create your models here.
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    summary = models.TextField(max_length = 500)
    specialty = models.ManyToManyField(FoodType)
    
    # This makes objects from this model readable in the admin and in shell
    def __unicode__(self):
        return '%s [%s]' % (self.user, self.pk)
    
    # if the UserProfile does not exist then create one
    # adds a property to the User model for convenience instead of having to do get_profile()
    # see http://www.turnkeylinux.org/blog/django-profile
    User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
 
---------------
 
# account/admin.py
from django.contrib import admin
 
# import your models here
# for convenience I put all the models into one admin.py file
from recipe.models import FoodType, Recipe
from account.models import UserProfile
 
# creating a list of the models since the register() function
# won't take all of them as arguments
registered_models = [FoodType, Recipe, UserProfile]
admin.site.register(registered_models)
 
---------
 
 
  1. In settings.py make sure you add your newly created apps and enable the django admin. Also add 'south' to it. If you don't already have south installed do $ sudo pip install south
  2. In urls.py comment out the parts about the admin (there are 3 lines you need to uncomment to get it working)
  3. Now let's sync our database by doing $ python manage.py syncdb
  4. Create a superuser when you are prompted as this is the account you will use to log in to the admin. 
  5. Do the initial migration (please review south documentation for full explanations. South is a lifesaver, trust me): 
  • $ python manage.py schemamigration account
  • $ python manage.py schemamigration recipe --initial
  • $ python manage.py migrate --fake

Now let's fire up our dev server $ python manage.py runserver

and go to http://127.0.0.1:8000/admin. If all goes well it should allow you to log in and see the models we've created. Test out our models by creating some objects in the admin. This is an awesome and easy way to see if our models make sense and test them.

I also highly recommend you use the shell and use the database API to try and retrieve the objects you've created in a pythonic way: $ python manage.py shell

Try these out:

from recipe.models import Recipe, FoodType

food = Recipe.objects.get(pk=1) #assuming you've created a recipe already

food.title

food.instructions

person = food.added_by

person.profile.summary

Task Discussion


  • Jessica Ledbetter   July 31, 2011, 5:54 p.m.

    Should the app names be "recipes" and "accounts" or "recipe" and "account"? I did mine as plural but can change :) One of those things I hope to get better at: learning what's convention.

    Also, curious why FoodType is in recipe/models.py  Is that because it's so simple?

    Why are instructions and ingredients CharField? Wouldn't TextField be better? Noticed when using admin that it was not as user friendly as if I used TextField. Or maybe we're going to use a widget so doesn't matter?

    I went ahead and am using sqlite3. Hopefully, that's alright. Wanted to experiment with it more :)

    Also, I had to add "--initial" for schemamigration commands.

    http://127.0.0.1:8000/admin is loading and all seems well. Added a recipe (one of my favs) and tested with the shell.

    Also documenting my mistake--er, learning by putting the code on github ;)

    https://github.com/jledbetter/cookbook

  • Alex Kehayias   July 31, 2011, 6:30 p.m.
    In Reply To:   Jessica Ledbetter   July 31, 2011, 5:54 p.m.

    You're right I forget to put the --initial

    I put FoodType under Recipe because it is so small and FoodType doesn't deserve to be in it's own app and models.py. Generally anything related to the app should go in it's models file. Having the account app is a convention I stick with because it's something you could add a lot of functionality to that deserves to be separated into it's own app (like your idea about integrating OpenID or say Facebook). 

    You can use TextField, it is probably more appropiate in this case. I'm going to change it to that actually as it may confuse people. Thanks!

    Sqllite is what I'm using just about always when running locally. You can create different settings files for different server configurations (like dev server or production server). 

    As for names of the apps I actually tend to plauralize them, but as long as you are consistent that's fine. It's a convention to make your Model classes singular though i.e. User rather than Users. 

  • Jessica Ledbetter   Aug. 5, 2011, 10:05 a.m.
    In Reply To:   Alex Kehayias   July 31, 2011, 6:30 p.m.

    Yes, I usually do plural for apps and singular for the model. Great :)

    I'm going to update my model then to use TextField. Makes it easier to use out of the box that way.

    I guess at the end of the class we will have a great set of recipes ;)