Wednesday, February 13, 2013

Mongo and Django

Like I described in the last post, I installed mongo and its python API mongoengine. Now I wanted to see if I could connect it to my preferred Python Web framework, Django.  A very nice tutorial on IBM DeveloperWorks got me interested in trying this too.

I use Eclipse and the very nice PyDev Python plug-in for Django development. The latter offers a little bit of Django integration into Eclipse, so a had a bare-bones Django site in no time at all, with the standard settings.py file. At this point, the site was based on SqlLite, Django's default.

Now the first bit is to connect to MongoDB inside settings.py, following the Mongoengine tutorial, like so:


import mongoengine  

 
 DEBUG = True  
 TEMPLATE_DEBUG = DEBUG  
 ADMINS = (  
   # ('Your Name', 'your_email@example.com'),  
 )  
 MANAGERS = ADMINS  
 DATABASES = {  
   'default': {  
     'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.  
     'NAME': 'C:\\Users\\me\\src\\test\\django_mongo\\sqlite.db',           # Or path to database file if using sqlite3.  
     # The following settings are not used with sqlite3:  
     'USER': '',  
     'PASSWORD': '',  
     'HOST': '',           # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.  
     'PORT': '',           # Set to empty string for default.  
   }  
 }  


 print 'Connection to MongoDB...',  
 mongoengine.connect('test')  
 print 'connected.'  

Additional lines that go to the bottom of settings.py are

 
AUTHENTICATION_BACKENDS = (  
   'mongoengine.django.auth.MongoEngineBackend',  
 )  
 SESSION_ENGINE = 'mongoengine.django.sessions'  

At this point I was able to run the Django shell, but of course had no models to play with. So I made an app with the standard Django manage.py startapp replicated the ones from the tutorial, except for the User model, which I imported from the mongoengine auth backend:

 from mongoengine import *  
 from mongoengine.django.auth import User  
   
 # Create your models here.  
 class Comment(EmbeddedDocument):  
   content = StringField()  
   name = StringField(max_length=120)  
   
 class Post(Document):  
   title = StringField(max_length=120, required=True)  
   author = ReferenceField(User, reverse_delete_rule=CASCADE)  
   tags = ListField(StringField(max_length=30))  
   comments = ListField(EmbeddedDocumentField(Comment))  
   
 class TextPost(Post):  
   content = StringField()  
   
 class ImagePost(Post):  
   image_path = StringField()  
   
 class LinkPost(Post):  
   link_url = StringField()  
   

Back in the Django shell, I got some FutureWarnings regarding inheritance soon defaulting to off, but I successfully tested
 In [2]: c=Comment(content='lala', name='Useful comment')  
 In [3]: u=User()  
 In [4]: u.username='me'  
 ...  
 In [30]: u  
 Out[30]: <User: me>  
   
 In [31]: User.objects.all()  
 Out[31]: []  
   
 In [32]: u.save()  
 Out[32]: <User: me>  
   
 In [33]: User.objects.all()  
 Out[33]: [<User: me>]  
   
 In [35]: p=Post(title='T', author=u, tags=['t1','t2'], comments=[c])  
   
 In [36]: p.save()  
 Out[36]: <Post: Post object>  
   
 In [38]: Post.objects.all()  
 Out[38]: [<Post: Post object>]  
   
 In [39]: Post.objects.all()[0]  
 Out[39]: <Post: Post object>  
   
 In [40]: Post.objects.all()[0].comments  
 Out[40]: [<Comment: Comment object>]  
   
 In [41]: Post.objects.filter(title='A')  
 Out[41]: []  
   
 In [42]: Post.objects.filter(title='T')  
 Out[42]: [<Post: Post object>]  
   
 In [43]: Post.objects.filter(title__in=['A','T'])  
 Out[43]: [<Post: Post object>]  

But I did get stuck at joins that span relations:
 In [54]: Post.objects.filter(author__username='me')  
 Out[54]: ---------------------------------------------------------------------------  
 InvalidQueryError             Traceback (most recent call last)  

Either I got something wrong or a bug tripped me! I will definitely crosspost this at Mongoengine and StackOverflow.

BTW, this was done with Django 1.6 20130110 dev trunk and Mongoengine 0.7.9 .

No comments: