diff --git a/docs/index.rst b/docs/index.rst
index c8b5515..ccc6bd4 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -6,7 +6,8 @@ Contents:
.. toctree::
:maxdepth: 0
- tutorial
+ tutorial-plain
+ tutorial-relay
filtering
authorization
debug
diff --git a/docs/tutorial-plain.rst b/docs/tutorial-plain.rst
new file mode 100644
index 0000000..6653b52
--- /dev/null
+++ b/docs/tutorial-plain.rst
@@ -0,0 +1,504 @@
+Introduction tutorial - Graphene and Django
+===========================================
+
+Graphene has a number of additional features that are designed to make
+working with Django *really simple*.
+
+Our primary focus here is to give a good understanding of how to connect models from Django ORM to graphene object types.
+
+A good idea is to check the `graphene `__ documentation first.
+
+Setup the Django project
+------------------------
+
+We will setup the project, create the following:
+
+- A Django project called ``cookbook``
+- An app within ``cookbook`` called ``ingredients``
+
+.. code:: bash
+
+ # Create the project directory
+ mkdir cookbook
+ cd cookbook
+
+ # Create a virtualenv to isolate our package dependencies locally
+ virtualenv env
+ source env/bin/activate # On Windows use `env\Scripts\activate`
+
+ # Install Django and Graphene with Django support
+ pip install django
+ pip install graphene_django
+
+ # Set up a new project with a single application
+ django-admin.py startproject cookbook . # Note the trailing '.' character
+ cd cookbook
+ django-admin.py startapp ingredients
+
+Now sync your database for the first time:
+
+.. code:: bash
+
+ python manage.py migrate
+
+Let's create a few simple models...
+
+Defining our models
+^^^^^^^^^^^^^^^^^^^
+
+Let's get started with these models:
+
+.. code:: python
+
+ # cookbook/ingredients/models.py
+ from django.db import models
+
+
+ class Category(models.Model):
+ name = models.CharField(max_length=100)
+
+ def __str__(self):
+ return self.name
+
+
+ class Ingredient(models.Model):
+ name = models.CharField(max_length=100)
+ notes = models.TextField()
+ category = models.ForeignKey(Category, related_name='ingredients')
+
+ def __str__(self):
+ return self.name
+
+Don't forget to create & run migrations:
+
+.. code:: bash
+
+ python manage.py makemigrations
+ python manage.py migrate
+
+Load some test data
+^^^^^^^^^^^^^^^^^^^
+
+Now is a good time to load up some test data. The easiest option will be
+to `download the
+ingredients.json `__
+fixture and place it in
+``cookbook/ingredients/fixtures/ingredients.json``. You can then run the
+following:
+
+.. code:: bash
+
+ $ python ./manage.py loaddata ingredients
+
+ Installed 6 object(s) from 1 fixture(s)
+
+Alternatively you can use the Django admin interface to create some data
+yourself. You'll need to run the development server (see below), and
+create a login for yourself too (``./manage.py createsuperuser``).
+
+Hello GraphQL - Schema and Object Types
+---------------------------------------
+
+In order to make queries to our Django project, we are going to need few things:
+
+* Schema with defined object types
+* A view, taking queries as input and returning the result
+
+GraphQL presents your objects to the world as a graph structure rather
+than a more hierarchical structure to which you may be accustomed. In
+order to create this representation, Graphene needs to know about each
+*type* of object which will appear in the graph.
+
+This graph also has a *root type* through which all access begins. This
+is the ``Query`` class below.
+
+This means, for each of our models, we are going to create a type, subclassing ``DjangoObjectType``
+
+After we've done that, we will list those types as fields in the ``Query`` class.
+
+Create ``cookbook/ingredients/schema.py`` and type the following:
+
+.. code:: python
+
+ # cookbook/ingredients/schema.py
+ import graphene
+
+ from graphene_django.types import DjangoObjectType
+
+ from cookbook.ingredients.models import Category, Ingredient
+
+
+ class CategoryType(DjangoObjectType):
+ class Meta:
+ model = Category
+
+
+ class IngredientType(DjangoObjectType):
+ class Meta:
+ model = Ingredient
+
+
+ class Query(graphene.AbstractType):
+ all_categories = graphene.List(CategoryType)
+ all_ingredients = graphene.List(IngredientType)
+
+ def resolve_all_categories(self, args, context, info):
+ return Category.objects.all()
+
+ def resolve_all_ingredients(self, args, context, info):
+ # We can easily optimize query count in the resolve method
+ return Ingredient.objects.select_related('category').all()
+
+
+Note that the above ``Query`` class is marked as 'abstract'. This is
+because we will now create a project-level query which will combine all
+our app-level queries.
+
+Create the parent project-level ``cookbook/schema.py``:
+
+.. code:: python
+
+ import graphene
+
+ import cookbook.ingredients.schema
+
+
+ class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
+ # This class will inherit from multiple Queries
+ # as we begin to add more apps to our project
+ pass
+
+ schema = graphene.Schema(query=Query)
+
+You can think of this as being something like your top-level ``urls.py``
+file (although it currently lacks any namespacing).
+
+Testing everything so far
+-------------------------
+
+We are going to do some configuration work, in order to have a working Django where we can test queries, before we move on, updating our schema.
+
+Update settings
+^^^^^^^^^^^^^^^
+
+Next, install your app and GraphiQL in your Django project. GraphiQL is
+a web-based integrated development environment to assist in the writing
+and executing of GraphQL queries. It will provide us with a simple and
+easy way of testing our cookbook project.
+
+Add ``ingredients`` and ``graphene_django`` to ``INSTALLED_APPS`` in ``cookbook/settings.py``:
+
+.. code:: python
+
+ INSTALLED_APPS = [
+ ...
+ # This will also make the `graphql_schema` management command available
+ 'graphene_django',
+
+ # Install the ingredients app
+ 'ingredients',
+ ]
+
+And then add the ``SCHEMA`` to the ``GRAPHENE`` config in ``cookbook/settings.py``:
+
+.. code:: python
+
+ GRAPHENE = {
+ 'SCHEMA': 'cookbook.schema.schema'
+ }
+
+Alternatively, we can specify the schema to be used in the urls definition,
+as explained below.
+
+Creating GraphQL and GraphiQL views
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Unlike a RESTful API, there is only a single URL from which GraphQL is
+accessed. Requests to this URL are handled by Graphene's ``GraphQLView``
+view.
+
+This view will serve as GraphQL endpoint. As we want to have the
+aforementioned GraphiQL we specify that on the params with ``graphiql=True``.
+
+.. code:: python
+
+ from django.conf.urls import url, include
+ from django.contrib import admin
+
+ from graphene_django.views import GraphQLView
+
+ urlpatterns = [
+ url(r'^admin/', admin.site.urls),
+ url(r'^graphql', GraphQLView.as_view(graphiql=True)),
+ ]
+
+
+If we didn't specify the target schema in the Django settings file
+as explained above, we can do so here using:
+
+.. code:: python
+
+ from django.conf.urls import url, include
+ from django.contrib import admin
+
+ from graphene_django.views import GraphQLView
+
+ from cookbook.schema import schema
+
+ urlpatterns = [
+ url(r'^admin/', admin.site.urls),
+ url(r'^graphql', GraphQLView.as_view(graphiql=True, schema=schema)),
+ ]
+
+
+
+Testing our GraphQL schema
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We're now ready to test the API we've built. Let's fire up the server
+from the command line.
+
+.. code:: bash
+
+ $ python ./manage.py runserver
+
+ Performing system checks...
+ Django version 1.9, using settings 'cookbook.settings'
+ Starting development server at http://127.0.0.1:8000/
+ Quit the server with CONTROL-C.
+
+Go to `localhost:8000/graphiql `__ and
+type your first query!
+
+.. code::
+
+ query {
+ allIngredients {
+ id
+ name
+ }
+ }
+
+If you are using the provided fixtures, you will see the following response:
+
+.. code::
+
+ {
+ "data": {
+ "allIngredients": [
+ {
+ "id": "1",
+ "name": "Eggs"
+ },
+ {
+ "id": "2",
+ "name": "Milk"
+ },
+ {
+ "id": "3",
+ "name": "Beef"
+ },
+ {
+ "id": "4",
+ "name": "Chicken"
+ }
+ ]
+ }
+ }
+
+You can experiment with ``allCategories`` too.
+
+Something to have in mind is the `auto camelcasing `__ that is happeing.
+
+
+Getting relations
+-----------------
+
+Right now, with this simple setup in place, we can query for relations too. This is where graphql becomes really powerful!
+
+For example, we may want to list all categories and in each category, all ingredients that are in that category.
+
+We can do that with the following query:
+
+.. code::
+
+ query {
+ allCategories {
+ id
+ name
+ ingredients {
+ id
+ name
+ }
+ }
+ }
+
+
+This will give you (in case you are using the fixtures) the following result:
+
+.. code::
+
+ {
+ "data": {
+ "allCategories": [
+ {
+ "id": "1",
+ "name": "Dairy",
+ "ingredients": [
+ {
+ "id": "1",
+ "name": "Eggs"
+ },
+ {
+ "id": "2",
+ "name": "Milk"
+ }
+ ]
+ },
+ {
+ "id": "2",
+ "name": "Meat",
+ "ingredients": [
+ {
+ "id": "3",
+ "name": "Beef"
+ },
+ {
+ "id": "4",
+ "name": "Chicken"
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+We can also list all ingredients and get information for the category they are in:
+
+.. code::
+
+ query {
+ allIngredients {
+ id
+ name
+ category {
+ id
+ name
+ }
+ }
+ }
+
+Getting single objects
+----------------------
+
+So far, we have been able to fetch list of objects and follow relation. But what about single objects?
+
+We can update our schema to support that, by adding new query for ``ingredient`` and ``category`` and adding arguments, so we can query for specific objects.
+
+.. code:: python
+
+ import graphene
+
+ from graphene_django.types import DjangoObjectType
+
+ from cookbook.ingredients.models import Category, Ingredient
+
+
+ class CategoryType(DjangoObjectType):
+ class Meta:
+ model = Category
+
+
+ class IngredientType(DjangoObjectType):
+ class Meta:
+ model = Ingredient
+
+
+ class Query(graphene.AbstractType):
+ category = graphene.Field(CategoryType,
+ id=graphene.Int(),
+ name=graphene.String())
+ all_categories = graphene.List(CategoryType)
+
+
+ ingredient = graphene.Field(IngredientType,
+ id=graphene.Int(),
+ name=graphene.String())
+ all_ingredients = graphene.List(IngredientType)
+
+ def resolve_all_categories(self, args, context, info):
+ return Category.objects.all()
+
+ def resolve_all_ingredients(self, args, context, info):
+ return Ingredient.objects.all()
+
+ def resolve_category(self, args, context, info):
+ id = args.get('id')
+ name = args.get('name')
+
+ if id is not None:
+ return Category.objects.get(pk=id)
+
+ if name is not None:
+ return Category.objects.get(name=name)
+
+ return None
+
+ def resolve_ingredient(self, args, context, info):
+ id = args.get('id')
+ name = args.get('name')
+
+ if id is not None:
+ return Ingredient.objects.get(pk=id)
+
+ if name is not None:
+ return Ingredient.objects.get(name=name)
+
+ return None
+
+Now, with the code in place, we can query for single objects.
+
+For example, lets query ``category``:
+
+
+.. code::
+
+ query {
+ category(id: 1) {
+ name
+ }
+ anotherCategory: category(name: "Dairy") {
+ ingredients {
+ id
+ name
+ }
+ }
+ }
+
+This will give us the following results:
+
+.. code::
+
+ {
+ "data": {
+ "category": {
+ "name": "Dairy"
+ },
+ "anotherCategory": {
+ "ingredients": [
+ {
+ "id": "1",
+ "name": "Eggs"
+ },
+ {
+ "id": "2",
+ "name": "Milk"
+ }
+ ]
+ }
+ }
+ }
+
+As an excercise, you can try making some queries to ``ingredient``.
+
+Something to keep in mind - since we are using one field several times in our query, we need `aliases `__
diff --git a/docs/tutorial.rst b/docs/tutorial-relay.rst
similarity index 99%
rename from docs/tutorial.rst
rename to docs/tutorial-relay.rst
index 56c492d..d544bac 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial-relay.rst
@@ -1,5 +1,5 @@
-Graphene-Django Tutorial
-========================
+Graphene-Django Tutorial using Relay
+====================================
Graphene has a number of additional features that are designed to make
working with Django *really simple*.