diff options
Diffstat (limited to 'recipe')
-rw-r--r-- | recipe/__init__.py | 0 | ||||
-rw-r--r-- | recipe/models.py | 90 | ||||
-rw-r--r-- | recipe/templatetags/__init__.py | 4 | ||||
-rw-r--r-- | recipe/templatetags/ingredientformat.py | 31 | ||||
-rw-r--r-- | recipe/tests.py | 23 | ||||
-rw-r--r-- | recipe/urls.py | 7 | ||||
-rw-r--r-- | recipe/views.py | 11 |
7 files changed, 166 insertions, 0 deletions
diff --git a/recipe/__init__.py b/recipe/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/recipe/__init__.py | |||
diff --git a/recipe/models.py b/recipe/models.py new file mode 100644 index 0000000..8463447 --- /dev/null +++ b/recipe/models.py | |||
@@ -0,0 +1,90 @@ | |||
1 | from django.db import models | ||
2 | from django.contrib import admin | ||
3 | from django.db.models import fields | ||
4 | |||
5 | |||
6 | class Unit(models.Model): | ||
7 | |||
8 | class Meta: | ||
9 | ordering = ('name',) | ||
10 | |||
11 | name = fields.CharField(max_length=100) | ||
12 | abbreviation = fields.CharField(max_length=10, blank=True, null=True) | ||
13 | |||
14 | def __unicode__(self): | ||
15 | return "{0} ({1})".format(self.name, self.abbreviation) | ||
16 | |||
17 | |||
18 | class Recipe(models.Model): | ||
19 | |||
20 | class Meta: | ||
21 | ordering = ('title',) | ||
22 | |||
23 | title = fields.CharField(max_length=100) | ||
24 | slug = fields.SlugField(max_length=150) | ||
25 | description = fields.TextField(blank=True, null=True) | ||
26 | servings = fields.IntegerField(blank=True, null=True) | ||
27 | instructions = fields.TextField() | ||
28 | oven_temp = fields.IntegerField(blank=True, null=True) | ||
29 | cook_time = fields.IntegerField(blank=True, null=True) | ||
30 | prep_time = fields.IntegerField(blank=True, null=True) | ||
31 | |||
32 | |||
33 | def __unicode__(self): | ||
34 | return self.title | ||
35 | |||
36 | |||
37 | class Ingredient(models.Model): | ||
38 | |||
39 | class Meta: | ||
40 | ordering = ('name',) | ||
41 | |||
42 | name = fields.CharField(max_length=100, unique=True) | ||
43 | |||
44 | def __unicode__(self): | ||
45 | return self.name | ||
46 | |||
47 | |||
48 | class RecipeIngredient(models.Model): | ||
49 | |||
50 | ingredient = models.ForeignKey(Ingredient) | ||
51 | units = models.ForeignKey(Unit) | ||
52 | quantity = fields.FloatField() | ||
53 | recipe = models.ForeignKey(Recipe) | ||
54 | |||
55 | def __unicode__(self): | ||
56 | return "{0} in {1}".format(self.ingredient.name, self.recipe.title) | ||
57 | |||
58 | |||
59 | class UnitAdmin(admin.ModelAdmin): | ||
60 | |||
61 | list_display = ('name', 'abbreviation') | ||
62 | ordering = ('name',) | ||
63 | |||
64 | |||
65 | class IngredientInline(admin.TabularInline): | ||
66 | |||
67 | model = RecipeIngredient | ||
68 | extra = 12 | ||
69 | |||
70 | |||
71 | class RecipeAdmin(admin.ModelAdmin): | ||
72 | |||
73 | list_display = ('title',) | ||
74 | inlines = (IngredientInline,) | ||
75 | search_fields = ('title',) | ||
76 | prepopulated_fields = { "slug": ("title",) } | ||
77 | |||
78 | |||
79 | class IngredientAdmin(admin.ModelAdmin): | ||
80 | |||
81 | list_display = ('name',) | ||
82 | search_fields = ('name',) | ||
83 | |||
84 | |||
85 | try: | ||
86 | admin.site.register(Unit, UnitAdmin) | ||
87 | admin.site.register(Ingredient, IngredientAdmin) | ||
88 | admin.site.register(Recipe, RecipeAdmin) | ||
89 | except admin.sites.AlreadyRegistered: | ||
90 | pass | ||
diff --git a/recipe/templatetags/__init__.py b/recipe/templatetags/__init__.py new file mode 100644 index 0000000..9bd6204 --- /dev/null +++ b/recipe/templatetags/__init__.py | |||
@@ -0,0 +1,4 @@ | |||
1 | from django import template | ||
2 | |||
3 | |||
4 | register = template.Library() | ||
diff --git a/recipe/templatetags/ingredientformat.py b/recipe/templatetags/ingredientformat.py new file mode 100644 index 0000000..fa75633 --- /dev/null +++ b/recipe/templatetags/ingredientformat.py | |||
@@ -0,0 +1,31 @@ | |||
1 | from recipe.templatetags import register | ||
2 | from django.template.defaultfilters import stringfilter | ||
3 | |||
4 | |||
5 | @register.filter(name="format_ingredient_quantity") | ||
6 | @stringfilter | ||
7 | def format_ingredient_quantity(value): | ||
8 | fractions = { | ||
9 | 0.125: '1/8', | ||
10 | 0.25 : '1/4', | ||
11 | 0.33 : '1/3', | ||
12 | 0.50 : '1/2', | ||
13 | 0.66 : '2/3', | ||
14 | 0.75 : '3/4', | ||
15 | } | ||
16 | |||
17 | value = float(value) | ||
18 | remainder = round(value % 1, 2) | ||
19 | whole = int(value - remainder) | ||
20 | |||
21 | if whole <= 0: | ||
22 | whole = "" | ||
23 | else: | ||
24 | whole = str(whole) | ||
25 | |||
26 | if remainder <= 0: | ||
27 | remainder = "" | ||
28 | else: | ||
29 | remainder = fractions.get(remainder, str(remainder)) | ||
30 | |||
31 | return "{0} {1}".format(whole, remainder) | ||
diff --git a/recipe/tests.py b/recipe/tests.py new file mode 100644 index 0000000..2247054 --- /dev/null +++ b/recipe/tests.py | |||
@@ -0,0 +1,23 @@ | |||
1 | """ | ||
2 | This file demonstrates two different styles of tests (one doctest and one | ||
3 | unittest). These will both pass when you run "manage.py test". | ||
4 | |||
5 | Replace these with more appropriate tests for your application. | ||
6 | """ | ||
7 | |||
8 | from django.test import TestCase | ||
9 | |||
10 | class SimpleTest(TestCase): | ||
11 | def test_basic_addition(self): | ||
12 | """ | ||
13 | Tests that 1 + 1 always equals 2. | ||
14 | """ | ||
15 | self.failUnlessEqual(1 + 1, 2) | ||
16 | |||
17 | __test__ = {"doctest": """ | ||
18 | Another way to test that 1 + 1 is equal to 2. | ||
19 | |||
20 | >>> 1 + 1 == 2 | ||
21 | True | ||
22 | """} | ||
23 | |||
diff --git a/recipe/urls.py b/recipe/urls.py new file mode 100644 index 0000000..4c937a0 --- /dev/null +++ b/recipe/urls.py | |||
@@ -0,0 +1,7 @@ | |||
1 | from django.conf.urls.defaults import patterns, url | ||
2 | |||
3 | |||
4 | urlpatterns = patterns('recipe.views', | ||
5 | url(r'^(?P<slug>[^/]+)', 'recipe_details'), | ||
6 | url(r'^$', 'recipe_list'), | ||
7 | ) | ||
diff --git a/recipe/views.py b/recipe/views.py new file mode 100644 index 0000000..3efdb9e --- /dev/null +++ b/recipe/views.py | |||
@@ -0,0 +1,11 @@ | |||
1 | from models import Recipe | ||
2 | from django.views.generic import list_detail | ||
3 | |||
4 | |||
5 | def recipe_list(request): | ||
6 | data = Recipe.objects.all() | ||
7 | return list_detail.object_list(request, queryset=data) | ||
8 | |||
9 | |||
10 | def recipe_details(request, slug): | ||
11 | return list_detail.object_detail(request, queryset=Recipe.objects.all(), slug=slug) | ||