Re: Absolute beginner question -- recipes

2016-03-07 Thread James Schneider
On Mon, Feb 29, 2016 at 4:51 AM, Simon Gunacker 
wrote:

> @Mike: the attempts (at least the ones I have seen) to store hierarchical
> data in relations [1] don't seem very intuitive to me. At least when it
> comes to query the data. Anyway: I would appreciate to be convinced by
> something else. However, I am afraid to kick off a completely different
> (yet interesting) discussion here. My current issue is how to access the
> additional fields of my M2M relationship. In addition to that I will think
> about hierarchical data in relational databases ;-)
>
>
For Django-specific guidance, have a look at Django-treebeard, which has
support for multiple hierarchical list strategies and a common API between
each of the strategies.

https://github.com/tabo/django-treebeard

Django-mptt (Modified Preorder Tree Traversal) also has some good resources:

https://github.com/django-mptt/django-mptt

There's also a host of other packages to manage trees of data:

https://www.djangopackages.com/grids/g/trees-and-graphs/

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciWQvWXcHa5C3RTEG95SdDhkLkKCTVUrWYsNv7-fZR6S7g%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-03-06 Thread Mike Dewhirst

On 7/03/2016 2:17 AM, Mike Dewhirst wrote:

On Thursday, March 3, 2016 at 3:22:04 AM UTC+11, Simon Gunacker wrote:

Inspired by Mike Dewhirsts suggestion on building hierachical
structures,



Not sure we are on the same page regarding "hierarchical". In the early
days hierarchical databases only had 1:n relationships IOW foreign keys
only. That is a very limiting thing. You have to turn your thinking
inside out to successfully represent the real world.  That's what I
meant. OTOH, RDBMS gives you everything you need to represent the real
world.

Â

I've made up another model:
|
classPart(models.Model):
    parts

=models.ForeignKey('Part',null=True,blank=True,default=None,related_name='pieces')
    name =models.CharField(max_length=200)
|


For this to work in Django the table name should probably be 'self'
rather than 'Part'. Haven't checked the docs on this recently.

Your 'parts' FK lets any Part be connected to exactly one or (null=True)
no other part. Is that what your real world is? If so, why did you use
plural nouns as the fieldname and related_name identifiers? Choosing
meaningful names is very helpful when you revisit your code in future.

If your real world scenario is the "bill of materials" I mentioned
earlier, you really need a many-to-many relationship between parts. That
means any part could be in a number of different parts (ie assemblies)
and assemblies themselves could actually be sub-assemblies in a finished
product - which amounts to an assembly of sub-assemblies. If so, we
might be getting close to your original recipes project.

Consider that what we need behind the scenes to represent a many-to-many
relationship is a bunch of records in a "through" table (let's call it
"Parts" plural) and all it needs is two FKs.


On rereading this, I should have said that for all the records (rows) in 
the "bunch" the fk1 always points to the same primary key in the Part 
table while every fk2 points to a different PK in the Part table.


Lets say fk1 points to the

precise row in the Part table which happens to be an assembly or
sub-assembly. fk1 in the through table would never point to a
stand-alone part. Then fk2 would point to another row in the Part table.
That other row is a part as well. It could represent a sub-assembly or a
stand-alone part but never a complete assembly.


And further, I neglected to mention that Django manages all this for you 
when you put ...


class Part(models.Model):
parts = ManyToManyField(null=True, blank=True, related_name=pieces")

... and working with this requires a few round-trips to the docs.

Mike



So when you want to know what all the parts are for an assembly you need
a view which understands your business logic and can run the appropriate
query to retrieve the results you want into a queryset, list or
whatever. Assuming the result you want is a list of an assembly's parts,
you would first identify the assembly in the Part table then query the
"through" table (Parts) for all the rows with fk1==Part
 ||
Â

Then I made my view:
|
classPartsView(generic.ListView):
    context_object_name='parts'
    model=Part
|


I have never tried generic views.

My typical approach is to create an arbitrary object (eg class
Assembly(object)) and use its __init__() method to instantiate an
assembly object with the queryset, list or whatever generated by the
code in the view. In the hypothetical example I'm conjuring up here we
would pass in Part.name as assembly.name and the queryset as assembly.qs
(or similar identifiers).

Â

But how should I design my template now?
|
Parts


{% for part in parts %}
 
{% endfor %}

|


Parts
{{ assembly.name }}
{% if assembly.qs %}

|{% for item in assembly.qs %}|
{{ item.fk2.name }}
{% endfor %}

{% else %}
No parts
{% endif %}

(each item represents a row in the through table Parts with fk2 being
the sub-assembly or part)
Â

That is all fine and dandy but what if you wanted more information about
the particular spot the part needed to be placed or the way it should be
aligned in the assembly? That information doesn't belong in the Parts
table for the part concerned because it might be in many assemblies.
Likewise it doesn't belong in the Parts table for the assembly concerned
because there could be heaps and heaps of parts involved. It actually
belongs in the "through" table Parts (plural). A single row in that
table uniquely defines the relationship between assembly and part. If we
add extra fields in the Parts "through" table those fields can carry
whatever extra info is required.

Note that the queryset performed in the view retrieved records from the
Parts table. That means if each row contains extra info you can simply
show it in your template as follows ...

|{% for item in assembly.qs %}|
{{ item.fk2.name }} Alignment {{ item.fk2.alignment }}
{% endfor %}

Hope this helps

Mike
Â


I already found different answ

Re: Absolute beginner question -- recipes

2016-03-06 Thread Mike Dewhirst
On Thursday, March 3, 2016 at 3:22:04 AM UTC+11, Simon Gunacker wrote:
>
> Inspired by Mike Dewhirsts suggestion on building hierachical structures, 
>


Not sure we are on the same page regarding "hierarchical". In the early 
days hierarchical databases only had 1:n relationships IOW foreign keys 
only. That is a very limiting thing. You have to turn your thinking inside 
out to successfully represent the real world.  That's what I meant. OTOH, 
RDBMS gives you everything you need to represent the real world. 

 

> I've made up another model:
> class Part(models.Model):
> parts = models.ForeignKey('Part', null=True, blank=True, default=None, 
> related_name='pieces')
> name = models.CharField(max_length=200)
>
>
For this to work in Django the table name should probably be 'self' rather 
than 'Part'. Haven't checked the docs on this recently.

Your 'parts' FK lets any Part be connected to exactly one or (null=True) no 
other part. Is that what your real world is? If so, why did you use plural 
nouns as the fieldname and related_name identifiers? Choosing meaningful 
names is very helpful when you revisit your code in future. 

If your real world scenario is the "bill of materials" I mentioned earlier, 
you really need a many-to-many relationship between parts. That means any 
part could be in a number of different parts (ie assemblies) and assemblies 
themselves could actually be sub-assemblies in a finished product - which 
amounts to an assembly of sub-assemblies. If so, we might be getting close 
to your original recipes project.

Consider that what we need behind the scenes to represent a many-to-many 
relationship is a bunch of records in a "through" table (let's call it 
"Parts" plural) and all it needs is two FKs. Lets say fk1 points to the 
precise row in the Part table which happens to be an assembly or 
sub-assembly. fk1 in the through table would never point to a stand-alone 
part. Then fk2 would point to another row in the Part table. That other row 
is a part as well. It could represent a sub-assembly or a stand-alone part 
but never a complete assembly. 

So when you want to know what all the parts are for an assembly you need a 
view which understands your business logic and can run the appropriate 
query to retrieve the results you want into a queryset, list or whatever. 
Assuming the result you want is a list of an assembly's parts, you would 
first identify the assembly in the Part table then query the "through" 
table (Parts) for all the rows with fk1==Part
 
 

> Then I made my view:
> class PartsView(generic.ListView):
> context_object_name='parts'
> model=Part
>
>
I have never tried generic views.

My typical approach is to create an arbitrary object (eg class 
Assembly(object)) and use its __init__() method to instantiate an assembly 
object with the queryset, list or whatever generated by the code in the 
view. In the hypothetical example I'm conjuring up here we would pass in 
Part.name as assembly.name and the queryset as assembly.qs (or similar 
identifiers).

 

> But how should I design my template now?
> Parts
>
> 
> {% for part in parts %}
>   
> {% endfor %}
> 
>
>
Parts
{{ assembly.name }}
{% if assembly.qs %}

{% for item in assembly.qs %}
{{ item.fk2.name }}
{% endfor %}

{% else %}
No parts
{% endif %}

(each item represents a row in the through table Parts with fk2 being the 
sub-assembly or part)
 

That is all fine and dandy but what if you wanted more information about 
the particular spot the part needed to be placed or the way it should be 
aligned in the assembly? That information doesn't belong in the Parts table 
for the part concerned because it might be in many assemblies. Likewise it 
doesn't belong in the Parts table for the assembly concerned because there 
could be heaps and heaps of parts involved. It actually belongs in the 
"through" table Parts (plural). A single row in that table uniquely defines 
the relationship between assembly and part. If we add extra fields in the 
Parts "through" table those fields can carry whatever extra info is 
required. 

Note that the queryset performed in the view retrieved records from the 
Parts table. That means if each row contains extra info you can simply show 
it in your template as follows ...

{% for item in assembly.qs %}
{{ item.fk2.name }} Alignment {{ item.fk2.alignment }}
{% endfor %}

Hope this helps

Mike
 


I already found different answers on the net reaching from 'impossible' to 
> 'with-tag' or 'install some add-ons'. According to Mikes former suggestion, 
> I expected something easy and elegant here ...
>
> regards, Simon
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users

Re: Absolute beginner question -- recipes

2016-03-02 Thread Simon Gunacker
Inspired by Mike Dewhirsts suggestion on building hierachical structures, 
I've made up another model:
class Part(models.Model):
parts = models.ForeignKey('Part', null=True, blank=True, default=None, 
related_name='pieces')
name = models.CharField(max_length=200)

Then I made my view:
class PartsView(generic.ListView):
context_object_name='parts'
model=Part

But how should I design my template now?
Parts


{% for part in parts %}
  
{% endfor %}


I already found different answers on the net reaching from 'impossible' to 
'with-tag' or 'install some add-ons'. According to Mikes former suggestion, 
I expected something easy and elegant here ...

regards, Simon


-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/abcfeada-4bd6-496f-a3f8-4678b08d8440%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-03-02 Thread Simon Gunacker
Thank you James. Taking your suggestion, I solved it!

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/7c7494ec-8ee5-4d14-bfae-a52297696e59%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread James Schneider
On Mon, Feb 29, 2016 at 5:57 AM, Simon Gunacker 
wrote:

> Thank you Florian. After James pointed out that I can access my steps (and
> the ingredients in some way) by just passing the recipe object to the
> templates context, I thought of reducing the view to a DetailView again.
> But I have to somehow access the ingredients from my template for now ...
>


The related models using a 'through' table also have access to the
'through' table itself. With your current setup, I think you can do this:


{% for steping in step.stepingredient_set.all %}
{{ steping.amount }} {{ steping.unit }} - {{ steping.ingredient
}}
{% empty %}
No ingredients needed for this step.
{% endfor %}


Optionally, for style points (and better human readability of the code),
you can also add a 'related_name' parameter to the FK's in the 'through'
table:

step = models.ForeignKey(Step, null=True,
related_name='step_ingredients')
ingredient = models.ForeignKey(Ingredient, null=True,
related_name='ingredient_steps')

That way, depending on the direction you are going, the call makes sense to
a human:


{% for steping in step.step_ingredients.all %}
{{ steping.amount }} {{ steping.unit }} - {{ steping.ingredient
}}
{% empty %}
No ingredients needed for this step.
{% endfor %}


I think that will work, although I haven't exactly tested this.

I'd highly recommend going with DetailView if you can. That makes your view
a whopping 2 or 3 lines.

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciWYj42TNJ4KeF4vFS6_wi0cghdCee%2Bu-_QJ0VP2uzyg-Q%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread Simon Gunacker
Thank you Florian. After James pointed out that I can access my steps (and 
the ingredients in some way) by just passing the recipe object to the 
templates context, I thought of reducing the view to a DetailView again. 
But I have to somehow access the ingredients from my template for now ...

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/b0c1408e-92bf-41a6-887a-8b5d03bd51f7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread Florian Schweikert
On 28/02/16 20:14, Simon Gunacker wrote:
> |
> def detail(request, pk):
> recipe = Recipe.objects.get(id=pk)
> recipe['steps'] = Steps.objects.filter(recipe_id=pk)
> template = loader.get_template('recipe/recipe_detail.html')
> context = {
> 'recipe': recipe,
> }
> return HttpResponse(template.render(context,request))
> |

OT:
Have a look at the render shortcut:
https://docs.djangoproject.com/en/1.9/topics/http/shortcuts/#render

| return render(request, 'recipe/recipe_detail.html', context)

Maybe you can simply use a generic DetailView:
https://docs.djangoproject.com/es/1.9/ref/class-based-views/generic-display/#detailview

--
Florian

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/56D44106.1070704%40ist-total.org.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread Simon Gunacker
@Mike: the attempts (at least the ones I have seen) to store hierarchical 
data in relations [1] don't seem very intuitive to me. At least when it 
comes to query the data. Anyway: I would appreciate to be convinced by 
something else. However, I am afraid to kick off a completely different 
(yet interesting) discussion here. My current issue is how to access the 
additional fields of my M2M relationship. In addition to that I will think 
about hierarchical data in relational databases ;-)

Thanks, Simon

--

http://www.slideshare.net/billkarwin/models-for-hierarchical-data

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/ee0101a5-1949-462a-8fd1-d50674cfdd89%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread Mike Dewhirst

On 29/02/2016 8:54 PM, Simon Gunacker wrote:

Well, as far as I know hierarchical relationships are hard to model in
relational databases;


Definitely incorrect. Hierarchical is merely a subset of relational. 
Relational can handle hierarchical 1:n:m very easily plus n:1, n:m as well.


Relational databases are the most widely used today because they can 
solve most real world modelling.


On that topic you should try to ignore database design initially and 
instead try to understand the real world relationships between your data 
types. Only then should you model the solution you need to provide.


I would be surprised if you couldn't solve most real world design 
problems with 1:1, 1:n, n:1 and n:m relationships.


The closer your schema is to the real world, the easier it will be to 
represent it in a relational (ie Django ORM) database. I believe best 
practice is to ignore shortcuts aimed at performance initially and make 
your design perfectly represent the real world. Only when it displays 
performance problems not fixable with caching should you try and 
introduce corner cutting in your design.




Mike


--
You received this message because you are subscribed to the Google Groups "Django 
users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/56D432D6.9030005%40dewhirst.com.au.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread Simon Gunacker
Ok ... but how can I access the additional information stored in 
StepIngredient then? 
And - to ask more general - is there a way to find all the "nested objects" 
attached to my current objects? Something to enter in the shell to see 
__all__ attributes; not just _meta.fields?

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/f3863003-fb81-4765-9a56-f0d221bb5a62%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread James Schneider
> Thank you James for pointing me at how to do my queries with django; I
can finally list my steps using:
>
> {% for step in recipe.steps.all %}
>
> within my template. However, given the model above I am still not sure
how to access a single steps ingredients ... any ideas or suggestions on my
current model?

Sure, just have another nested {% for ingredient in step.ingredients.all %}

You should also change the 'ingredient' field to 'ingredients' in your Step
model (reflected in my loop above). Makes it easier to read and indicate
that you'll need the .all in the template (or elsewhere) if the attribute
name is plural. Otherwise you are querying using step.ingredient, and
expecting a list of multiple ingredients back.

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciXjKnTgCpJcCT8hxP2gRgLOqA6DygkqT0WZr5Nqm8vQUQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread Simon Gunacker
Hey everybody,

thank you very much for your answers. I think I have already learned a lot 
from you! Well - there is quite a difference between stepping through a 
tutorial and trying to do something on my own. Regarding Mikes question 
whether a step of a recipe should be a sub-recipe. Well, as far as I know 
hierarchical relationships are hard to model in relational databases; 
that's why I kept my hands off! My decision to create a recipe app has a 
simple reason: I read some comparisons between django and ruby on rails and 
I decided to go for django since it seems to leave more freedom. I found a 
RoR tutorial on creating a recipe app some time ago and I am trying to do 
the same thing in django now. 

Concerning my model - this is how it looks like:

from __future__ import unicode_literals

from django.db import models

class Unit(models.Model):
abbreveation = models.CharField(max_length=5, primary_key=True)
description = models.CharField(max_length=50)

def __str__(self):
return "%s (%s)" % (self.description, self.abbreveation)

class Ingredient(models.Model):
name = models.CharField(max_length=255)

def __str__(self):
return self.name

class Step(models.Model):
name = models.CharField(max_length=255, blank=True)
recipe = models.ForeignKey('Recipe', related_name='steps', on_delete=
models.CASCADE, null=True)
description = models.TextField()
ingredient = models.ManyToManyField(Ingredient, through='StepIngredient'
)

def __str__(self):
if (self.name == ''):
return "Step %d" % self.id
else:
return "Step %d (%s)" % (self.id, self.name)

# additional information for many to many relationship between schritt and 
zutat
class StepIngredient(models.Model):
class Meta:
unique_together = (('step', 'ingredient'),)
step = models.ForeignKey(Step, null=True)
ingredient = models.ForeignKey(Ingredient, null=True)
amount = models.DecimalField(max_digits=7, decimal_places=3)
unit = models.ForeignKey(Unit, null=True)

def __str__(self):
return "%d %s %s" % (self.amount, self.unit.abbreveation, self.
ingredient)

class Recipe(models.Model):
name = models.CharField(max_length=255)

# file will be uploaded to MEDIA_ROOT/images
# TODO: Upload works but link fails. Maybe sth. wrong with MEDIA_URL???
photo = models.ImageField(upload_to='images/', null=True)
portionen = models.IntegerField(default=2)

def __str__(self):
return self.name

Thank you James for pointing me at how to do my queries with django; I can 
finally list my steps using:

{% for step in recipe.steps.all %}

within my template. However, given the model above I am still not sure how 
to access a single steps ingredients ... any ideas or suggestions on my 
current model?

Thanks, Simon



-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/cef5e940-6947-4fe2-b20b-1c805ea09572%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-29 Thread James Schneider
On Sun, Feb 28, 2016 at 11:45 PM, Rahul Gandhi 
wrote:

> I might be wrong here, but this is what I understand:
>
> Let's say you have something like this:
>
>
> class Recipe(models.Model):
> name = models.CharField(max_length=255)
> description = models.TextField()
>
>
> class Step(models.Model):
> step_number = models.IntegerField()
> description = models.TextField()
> recipe = models.ForeignKey(Recipe)
>
>
> now, if I do the following in the shell:
>
> recipe = Recipe.objects.get(id=1)
> recipe.steps
>
> wouldn't this give an error?
>

> To get the step, I could do something like
> recipe.step_set
>
> but I don't think I'll be able to do recipe.steps
>
>
Given that model, you're right, sorry about that. My brain was moving
faster than my fingers. All of my mentions of recipe.steps were meant as a
reference to recipe.step_set. In my head I had already set the related_name
to 'steps', like so:

recipe = models.ForeignKey(Recipe, related_name='steps')

This way you can use recipe.steps rather than recipe.step_set. Both are
equivalent, but the custom related_name is easier to track for a human. The
relation does act like its own manager though, so you would actually have
to say recipe.steps.all() to get all of the steps (since a separate query
is used to pull all of the steps). The template code would also have to be
adjusted to include the .all (no parenthesis there). Also be sure to
determine whether or not you should use prefetch_related for your list
views (
https://docs.djangoproject.com/en/1.9/ref/models/querysets/#prefetch-related
).

However, this model does match what I assumed you had. I'm also assuming
that you have a M2M relationship with Ingredient with a custom 'through'
table so that you can match steps with ingredients and store other things
like measurements on that relation?

I would make a suggestion, though. Instead of using a 'step_number', you
should look at using django-ordered-model instead. It does a very good job
of keeping things, well, ordered. It also has other functionality like
performing a renumber automatically if you decide that step 2 should
actually be step 18 (and renumbers all of the other steps appropriately).
The 'order' that is uses is zero-based, but you can add a simple property
step_number that returns self.order + 1 (and sets the order correctly if
you are renumbering by step). You'll also need to implement their
'order_with_respect_to', probably point it at the recipe field.

https://github.com/bfirsh/django-ordered-model

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciUw-Yqv3cK-M_n%2B%2BqutU8BDzbbYGhqJYxS3M%3DmX%2BqKYwA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread Rahul Gandhi
I might be wrong here, but this is what I understand:

Let's say you have something like this:


class Recipe(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()


class Step(models.Model):
step_number = models.IntegerField()
description = models.TextField()
recipe = models.ForeignKey(Recipe)


now, if I do the following in the shell:

recipe = Recipe.objects.get(id=1)
recipe.steps

wouldn't this give an error?

To get the step, I could do something like 
recipe.step_set

but I don't think I'll be able to do recipe.steps



On Monday, February 29, 2016 at 8:08:35 AM UTC+5:30, James Schneider wrote:
>
>
>
> On Sun, Feb 28, 2016 at 11:14 AM, Simon Gunacker  > wrote:
>
>> Dear Django Community,
>>
>> as a first django project I tried to write a site to manage cooking 
>> recipes. My model is quite simple: 
>>
>> * 1 recipe has n steps 
>> * 1 step has a description and n ingredients, each of a certain amount 
>> defined by a certain unit 
>>
>> all in all, I have 5 tables (Recipe, Step, Ingredient, Unit, 
>> StepIngredient).
>>
>> After reading through some documentation and trying around a little bit, 
>> I got my model and my admin site (I had to install django-nested-inline for 
>> the admin site to fit my expectations).
>>
>> Now I am struggeling with my views. There is a simple index view wich 
>> basically lists all recipes:
>>
>> class IndexView(generic.ListView):
>> context_object_name = 'recipes_list'
>>
>> def get_queryset(self):
>> return Recipe.objects.all()
>>
>>
> You can actually get rid of the get_queryset() override entirely here by 
> properly setting the default view model to Recipe.
>
>  
>
>> The hard part is setting up the details view. It is supposed to show the 
>> recipes name as a title and then list all the required ingredients and all 
>> the required steps. It tried something like: 
>>
>> def detail(request, pk):
>> recipe = Recipe.objects.get(id=pk)
>> recipe['steps'] = Steps.objects.filter(recipe_id=pk)
>> template = loader.get_template('recipe/recipe_detail.html')
>> context = {
>> 'recipe': recipe,
>> }
>> return HttpResponse(template.render(context, request))
>>
>> but it seems I am not allowed to modify the recipes object. Any ideas how 
>> to pass all the data which belongs to recipe to the template?
>>
>>
> Whoa...why are you manually setting recipe['steps']? Isn't there already a 
> relationship between Recipe (the model) and Step (Step should have a FK 
> back to Recipe)? You should not need an explicit second call to 
> Step.objects. If that call is necessary, then I would be highly suspicious 
> that your models are not defined properly (sanely).
>
> I would remove that second line where you set recipe['steps'] entirely. If 
> that breaks something, your models are probably incorrect.
>
> Assuming you run just the first line (recipe = Recipe.objects.get(id=pk)), 
> you should be able to do the following in the Django shell:
>
> recipe.steps # return a list of all of the steps associated with that 
> recipe
>
> recipe.steps[2].ingredients # return a list of ingredients for what is 
> presumably step 3 of the recipe
>
> There shouldn't be any need for manually querying for the steps or their 
> ingredients after the original Recipe.objects.get() call. 
>
> -James
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/3e8828f2-a104-4855-a728-58c9b8362347%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread Mike Dewhirst

On 29/02/2016 2:09 PM, James Schneider wrote:

Again, I'm making some assumptions about your models. If the above code
snippets don't work (aside from typos), please post up your models.py
file(s) so that we can adjust accordingly.



I think James is right. Maybe the answer to the above question is in 
your subject line.


If I was doing a recipe app I would need to scratch my head. For 
example, do I permit an ingredient to also be a recipe? In other words, 
are ingredients simply raw materials or can they be separate 
concoctions. I'm no chef but I suspect recipes include separately 
prepared components which are brought together during the cooking 
process or at the latest just before serving.


Maybe your "step" is a sub-recipe.

So the real question is about your expertise. If you are a chef all you 
need here is how to do many-to-many relationships. There must be heaps 
of manufacturer apps out there. They generally go under the label of 
"bill-of-materials". It seems to me quite similar to recipes.


Anyway ...

I'm building a much simpler ingredients system with substances and 
mixtures where a mixture is a substance having relationships with other 
substances. Here is my setup:


class Substance(models.Model):
ingredients = models.ManyToManyField('self', symmetrical=False, 
blank=True, through='Substance_Ingredients')

...

class Substance_Ingredients(models.Model):
substance = models.ForeignKey('Substance', null=True, blank=True,
related_name='base_substance')
ingredient = models.ForeignKey('Substance', null=True, blank=True,)
proportion = models.DecimalField(null=True, blank=True)
...

Hope this helps

Mike

--
You received this message because you are subscribed to the Google Groups "Django 
users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/56D3C15E.5050507%40dewhirst.com.au.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread James Schneider
On Sun, Feb 28, 2016 at 12:23 PM, Simon Gunacker 
wrote:

> Thank you Rahul,
>
> I actually tried that an this is possible for the relationship between a
> recipe and its steps. But when it comes to the ingredients for a single
> step, I cannot do this any more since the ingredients depend on steps
> again. After reading your suggestion I thought about it once more and I
> came up with the following solution:
>
> def detail(request, pk):
> recipe = Recipe.objects.get(id=pk)
> steps = Step.objects.filter(recipe_id=pk)
>
> ingredients = dict()
> for step in steps:
> ingredients[step.id] = StepIngredients.objects.filter(step_id=step
> .id)
>
> template = loader.get_template('recipe/rezept_detail.html')
> context = {
> 'recipe': recipe,
> 'steps': steps,
> 'ingredients': ingredients
> }
> return HttpResponse(template.render(context, request))
>
>
Please review how the Django ORM works. You're creating much more work for
yourself and your application. 50% of the code in this block can be removed.

https://docs.djangoproject.com/en/1.9/intro/tutorial02/#playing-with-the-api
https://docs.djangoproject.com/es/1.9/topics/db/queries/
https://docs.djangoproject.com/en/1.9/topics/db/queries/#related-objects


def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
template = loader.get_template('recipe/rezept_detail.html')
context = {
'recipe': recipe,
}
return HttpResponse(template.render(context, request))


I've already mentioned that separate calls to Step.objects are not
necessary, because recipe.steps contains the results of such a query
already.

The same applies to the ingredients for each step.

for step in recipe.steps:
print('Ingredients: '.format(step.ingredients))
# or
for ingredient in step.ingredients:
print(ingredient)

There is no need to have separate context variables within the template
context for each piece of the recipe. All of the information that you are
manually extracting is already available in the original object that was
requested. The only exception that I would make is if you needed a separate
list of all ingredients for all steps in one big list, which is much more
difficult to extract. Even then, though, that sore of query is probably
better handled by a model manager method that can be accessed via the
template.

Of course, everything I'm saying is predicated on a decent model design. It
could be that your current model structure doesn't allow for taking
advantage of the ORM capabilities. If that's the case, though...you may
want to review it.



> However, when it comes to the view, it does not work any more:
> {{ recipe.name }}
>
> 
> {% for step in steps %}
>
>   
> 
> {% for ingredient in ingredients.step.id %}
>   {{ ingredient.amount }}
> {% endfor %}
> 
>
> {{ step.description }}
>   
>
> {% endfor %}
> 
>
> According to what I found on google, the django template language cannot
> deal with accessing dictionary entries using variables as keys. What is the
> django-way of solving this problem? Any ideas?
>

Yes, the template syntax is limited, intentionally. Assuming that you take
my previous advice and utilize the recipe object directly:

{{ recipe.name }}


{% for step in recipe.steps %}

  

{% for ingredient in step.ingredients %}
  {{ ingredient.amount }}
{% endfor %}


{{ step.description }}
  

{% endfor %}


I have no idea why you are referring to ingredients.step.id in your
template, it doesn't even make sense with the code you have (which is
probably why things aren't behaving the way you'd expect). There really
shouldn't be a need to ever refer to .id or .pk within a template, unless
you are specifically printing out those values for an input field name or
using {% url %}.

Again, I'm making some assumptions about your models. If the above code
snippets don't work (aside from typos), please post up your models.py
file(s) so that we can adjust accordingly.

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciWPFUqwe9VXKTFWBJhQQUuNAEgtMFOjGxpxBtongM2SSg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread James Schneider
On Sun, Feb 28, 2016 at 11:47 AM, Rahul Gandhi 
wrote:

> You could do something like this:
>
> def detail(request, pk):
> recipe = Recipe.objects.get(id=pk)
> steps = Steps.objects.filter(recipe_id=pk)
> template = loader.get_template('recipe/recipe_detail.html')
> context = {
> 'recipe': recipe,
> 'steps': steps
> }
> return HttpResponse(template.render(context, request))
>
> And make appropriate changes to your template.
>
>
There's really no point is doing this. Within the template, {{ recipe.steps
}} should already contain everything that {{ steps }} would contain in this
instance. All you've done is created extra work for the ORM and added
complication to the code.

Your context should only contain { 'recipe': recipe } at this point.
Frankly, I'm not sure if it even needs that if you are using the built-in
class-based views such as DetailView.

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciX0hufY9%2ByfGpM12%3DCzQK7q2AfDTxikJupppoTeXk%2BdiA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread James Schneider
On Sun, Feb 28, 2016 at 11:14 AM, Simon Gunacker 
wrote:

> Dear Django Community,
>
> as a first django project I tried to write a site to manage cooking
> recipes. My model is quite simple:
>
> * 1 recipe has n steps
> * 1 step has a description and n ingredients, each of a certain amount
> defined by a certain unit
>
> all in all, I have 5 tables (Recipe, Step, Ingredient, Unit,
> StepIngredient).
>
> After reading through some documentation and trying around a little bit, I
> got my model and my admin site (I had to install django-nested-inline for
> the admin site to fit my expectations).
>
> Now I am struggeling with my views. There is a simple index view wich
> basically lists all recipes:
>
> class IndexView(generic.ListView):
> context_object_name = 'recipes_list'
>
> def get_queryset(self):
> return Recipe.objects.all()
>
>
You can actually get rid of the get_queryset() override entirely here by
properly setting the default view model to Recipe.



> The hard part is setting up the details view. It is supposed to show the
> recipes name as a title and then list all the required ingredients and all
> the required steps. It tried something like:
>
> def detail(request, pk):
> recipe = Recipe.objects.get(id=pk)
> recipe['steps'] = Steps.objects.filter(recipe_id=pk)
> template = loader.get_template('recipe/recipe_detail.html')
> context = {
> 'recipe': recipe,
> }
> return HttpResponse(template.render(context, request))
>
> but it seems I am not allowed to modify the recipes object. Any ideas how
> to pass all the data which belongs to recipe to the template?
>
>
Whoa...why are you manually setting recipe['steps']? Isn't there already a
relationship between Recipe (the model) and Step (Step should have a FK
back to Recipe)? You should not need an explicit second call to
Step.objects. If that call is necessary, then I would be highly suspicious
that your models are not defined properly (sanely).

I would remove that second line where you set recipe['steps'] entirely. If
that breaks something, your models are probably incorrect.

Assuming you run just the first line (recipe = Recipe.objects.get(id=pk)),
you should be able to do the following in the Django shell:

recipe.steps # return a list of all of the steps associated with that recipe

recipe.steps[2].ingredients # return a list of ingredients for what is
presumably step 3 of the recipe

There shouldn't be any need for manually querying for the steps or their
ingredients after the original Recipe.objects.get() call.

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciWUCC3QfHdzCCEE8o9H8i%2BX1XoyFyf%2BOhBhF8BMh%2Bv5%2Bg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread Simon Gunacker
Thank you Rahul,

I actually tried that an this is possible for the relationship between a 
recipe and its steps. But when it comes to the ingredients for a single 
step, I cannot do this any more since the ingredients depend on steps 
again. After reading your suggestion I thought about it once more and I 
came up with the following solution: 

def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
steps = Step.objects.filter(recipe_id=pk)

ingredients = dict()
for step in steps:
ingredients[step.id] = StepIngredients.objects.filter(step_id=step.
id)

template = loader.get_template('recipe/rezept_detail.html')
context = {
'recipe': recipe,
'steps': steps,
'ingredients': ingredients
}
return HttpResponse(template.render(context, request))

However, when it comes to the view, it does not work any more:
{{ recipe.name }}


{% for step in steps %}

  

{% for ingredient in ingredients.step.id %}
  {{ ingredient.amount }}
{% endfor %}


{{ step.description }}
  

{% endfor %}


According to what I found on google, the django template language cannot 
deal with accessing dictionary entries using variables as keys. What is the 
django-way of solving this problem? Any ideas?

Thank you!

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/c0974be2-ad5b-44bd-b08b-2fa0a18eee5a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread Rahul Gandhi
You could do something like this:

def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
steps = Steps.objects.filter(recipe_id=pk)
template = loader.get_template('recipe/recipe_detail.html')
context = {
'recipe': recipe,
'steps': steps
}
return HttpResponse(template.render(context, request))

And make appropriate changes to your template. 

On Monday, February 29, 2016 at 1:00:25 AM UTC+5:30, Simon Gunacker wrote:
>
> Dear Django Community,
>
> as a first django project I tried to write a site to manage cooking 
> recipes. My model is quite simple: 
>
> * 1 recipe has n steps 
> * 1 step has a description and n ingredients, each of a certain amount 
> defined by a certain unit 
>
> all in all, I have 5 tables (Recipe, Step, Ingredient, Unit, 
> StepIngredient).
>
> After reading through some documentation and trying around a little bit, I 
> got my model and my admin site (I had to install django-nested-inline for 
> the admin site to fit my expectations).
>
> Now I am struggeling with my views. There is a simple index view wich 
> basically lists all recipes:
>
> class IndexView(generic.ListView):
> context_object_name = 'recipes_list'
>
> def get_queryset(self):
> return Recipe.objects.all()
>
> The hard part is setting up the details view. It is supposed to show the 
> recipes name as a title and then list all the required ingredients and all 
> the required steps. It tried something like: 
>
> def detail(request, pk):
> recipe = Recipe.objects.get(id=pk)
> recipe['steps'] = Steps.objects.filter(recipe_id=pk)
> template = loader.get_template('recipe/recipe_detail.html')
> context = {
> 'recipe': recipe,
> }
> return HttpResponse(template.render(context, request))
>
> but it seems I am not allowed to modify the recipes object. Any ideas how 
> to pass all the data which belongs to recipe to the template?
>
> Thank you,
>
> Simon
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/607fb0d4-844a-41c8-99e2-a914401b65ae%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Absolute beginner question -- recipes

2016-02-28 Thread Rahul Gandhi

You could do something like this:

Instead of 

recipe['steps'] = Steps.objects.filter(recipe_id=pk)

Do this:

steps = Steps.objects.filter(recipe_id=pk)
context = {
'recipe': recipe,

}





On Monday, February 29, 2016 at 1:00:25 AM UTC+5:30, Simon Gunacker wrote:
>
> Dear Django Community,
>
> as a first django project I tried to write a site to manage cooking 
> recipes. My model is quite simple: 
>
> * 1 recipe has n steps 
> * 1 step has a description and n ingredients, each of a certain amount 
> defined by a certain unit 
>
> all in all, I have 5 tables (Recipe, Step, Ingredient, Unit, 
> StepIngredient).
>
> After reading through some documentation and trying around a little bit, I 
> got my model and my admin site (I had to install django-nested-inline for 
> the admin site to fit my expectations).
>
> Now I am struggeling with my views. There is a simple index view wich 
> basically lists all recipes:
>
> class IndexView(generic.ListView):
> context_object_name = 'recipes_list'
>
> def get_queryset(self):
> return Recipe.objects.all()
>
> The hard part is setting up the details view. It is supposed to show the 
> recipes name as a title and then list all the required ingredients and all 
> the required steps. It tried something like: 
>
> def detail(request, pk):
> recipe = Recipe.objects.get(id=pk)
> recipe['steps'] = Steps.objects.filter(recipe_id=pk)
> template = loader.get_template('recipe/recipe_detail.html')
> context = {
> 'recipe': recipe,
> }
> return HttpResponse(template.render(context, request))
>
> but it seems I am not allowed to modify the recipes object. Any ideas how 
> to pass all the data which belongs to recipe to the template?
>
> Thank you,
>
> Simon
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/90fe91f6-f752-45aa-9ea9-04d16da71178%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Absolute beginner question -- recipes

2016-02-28 Thread Simon Gunacker
Dear Django Community,

as a first django project I tried to write a site to manage cooking 
recipes. My model is quite simple: 

* 1 recipe has n steps 
* 1 step has a description and n ingredients, each of a certain amount 
defined by a certain unit 

all in all, I have 5 tables (Recipe, Step, Ingredient, Unit, 
StepIngredient).

After reading through some documentation and trying around a little bit, I 
got my model and my admin site (I had to install django-nested-inline for 
the admin site to fit my expectations).

Now I am struggeling with my views. There is a simple index view wich 
basically lists all recipes:

class IndexView(generic.ListView):
context_object_name = 'recipes_list'

def get_queryset(self):
return Recipe.objects.all()

The hard part is setting up the details view. It is supposed to show the 
recipes name as a title and then list all the required ingredients and all 
the required steps. It tried something like: 

def detail(request, pk):
recipe = Recipe.objects.get(id=pk)
recipe['steps'] = Steps.objects.filter(recipe_id=pk)
template = loader.get_template('recipe/recipe_detail.html')
context = {
'recipe': recipe,
}
return HttpResponse(template.render(context, request))

but it seems I am not allowed to modify the recipes object. Any ideas how 
to pass all the data which belongs to recipe to the template?

Thank you,

Simon

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/13050a08-1f80-41d0-9739-bf9dae9ef0d3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.