A simple CRUD app with Django and Mongoengine
There are several possibilities to use MongoDB in Django:
Django MongoDB uses django-nonrel, which is a fork based on Django 1.3.
I don’t like this idea, because now Django 1.5 is ready to out.
Beetween Mongoengine and MongoKit, I like more Mongoengine. There are several comparative articles:
So I created a simple CRUD app using Mongoengine.
The model definition in Mongoengine looks like in Django.
class Post(Document):
user = ReferenceField(User, reverse_delete_rule=CASCADE)
title = StringField(max_length=200, required=True)
text = StringField(required=True)
text_length = IntField()
date_modified = DateTimeField(default=datetime.now)
is_published = BooleanField()
tags = ListField(ReferenceField(Tag))
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
self.text_length = len(self.text)
return super(Post, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('post-detail', args=[self.id])
You can find the full fields list in the documentation.
The default TEST_RUNNER throws error: django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.
I used MongoTestSuiteRunner and MongoTestCase from https://github.com/lig/mongoengine/blob/django-testing-utils/mongoengine/django/tests.py.
There are several problems with using of generic views.
- Mongoengine document has not
_meta.app_label
,_meta.object_name
properties - There is no ModelForm for create, update views
It can be solved by using django-mongogeneric and django-mongodbforms.
In my app I’ve just overrided get_template_names
, get_query_set
, get_object
methods and set context_object_name
property.
class TagListView(ListView):
model = Tag
context_object_name = "tag_list"
def get_template_names(self):
return ["blog/tag_list.html"]
def get_queryset(self):
return Tag.objects
And emulated ModelForm with simple Form.
forms.py
class PostForm(forms.Form):
title = forms.CharField(max_length=255)
text = forms.CharField(widget=forms.widgets.Textarea())
is_published = forms.BooleanField(required=False)
tags = forms.MultipleChoiceField(
widget=forms.widgets.CheckboxSelectMultiple(),
required=False)
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance', None)
super(PostForm, self).__init__(*args, **kwargs)
self.fields['tags'].choices = [(tag.id, tag.title) for tag in Tag.objects]
if self.instance:
self.fields['title'].initial = self.instance.title
self.fields['text'].initial = self.instance.text
self.fields['is_published'].initial = self.instance.is_published
self.fields['tags'].initial = [tag.id for tag in self.instance.tags]
def save(self, commit=True):
post = self.instance if self.instance else Post()
post.title = self.cleaned_data['title']
post.text = self.cleaned_data['text']
post.is_published = self.cleaned_data['is_published']
post.tags = Tag.objects(id__in=self.cleaned_data['tags'])
if commit:
post.save()
return post
views.py:
class PostCreateView(CreateView):
model = Post
form_class = PostForm
...