diff options
| author | Robin Munn <robin.munn@gmail.com> | 2007-01-31 23:43:09 +0000 |
|---|---|---|
| committer | Robin Munn <robin.munn@gmail.com> | 2007-01-31 23:43:09 +0000 |
| commit | fe361e678a46dc4c717c79c2f12b3ba32293b81a (patch) | |
| tree | 8f42488e7d95244bab3db7b2bf934e006940521a /tests/modeltests | |
| parent | 122426e7453ed638a0c5be7e8b925adcddea3889 (diff) | |
Merged revisions 4186 to 4454 from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/sqlalchemy@4455 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests/modeltests')
| -rw-r--r-- | tests/modeltests/basic/models.py | 15 | ||||
| -rw-r--r-- | tests/modeltests/custom_columns/models.py | 92 | ||||
| -rw-r--r-- | tests/modeltests/generic_relations/models.py | 34 | ||||
| -rw-r--r-- | tests/modeltests/get_object_or_404/__init__.py | 0 | ||||
| -rw-r--r-- | tests/modeltests/get_object_or_404/models.py | 86 | ||||
| -rw-r--r-- | tests/modeltests/lookup/models.py | 15 | ||||
| -rw-r--r-- | tests/modeltests/many_to_many/models.py | 26 | ||||
| -rw-r--r-- | tests/modeltests/model_forms/__init__.py | 0 | ||||
| -rw-r--r-- | tests/modeltests/model_forms/models.py | 284 | ||||
| -rw-r--r-- | tests/modeltests/or_lookups/models.py | 15 | ||||
| -rw-r--r-- | tests/modeltests/serializers/models.py | 21 | ||||
| -rw-r--r-- | tests/modeltests/test_client/views.py | 2 |
12 files changed, 558 insertions, 32 deletions
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py index 5638865f31..1663068892 100644 --- a/tests/modeltests/basic/models.py +++ b/tests/modeltests/basic/models.py @@ -10,6 +10,9 @@ class Article(models.Model): headline = models.CharField(maxlength=100, default='Default headline') pub_date = models.DateTimeField() + class Meta: + ordering = ('pub_date','headline') + def __str__(self): return self.headline @@ -245,7 +248,7 @@ datetime.datetime(2005, 7, 28, 0, 0) # Slices (without step) are lazy: >>> Article.objects.all()[0:5].filter() -[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Fourth article>, <Article: Article 6>] +[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Article 6>, <Article: Default headline>] # Slicing again works: >>> Article.objects.all()[0:5][0:2] @@ -253,17 +256,17 @@ datetime.datetime(2005, 7, 28, 0, 0) >>> Article.objects.all()[0:5][:2] [<Article: Area woman programs in Python>, <Article: Second article>] >>> Article.objects.all()[0:5][4:] -[<Article: Article 6>] +[<Article: Default headline>] >>> Article.objects.all()[0:5][5:] [] # Some more tests! >>> Article.objects.all()[2:][0:2] -[<Article: Third article>, <Article: Fourth article>] +[<Article: Third article>, <Article: Article 6>] >>> Article.objects.all()[2:][:2] -[<Article: Third article>, <Article: Fourth article>] +[<Article: Third article>, <Article: Article 6>] >>> Article.objects.all()[2:][2:3] -[<Article: Article 6>] +[<Article: Default headline>] # Note that you can't use 'offset' without 'limit' (on some dbs), so this doesn't work: >>> Article.objects.all()[2:] @@ -312,7 +315,7 @@ AttributeError: Manager isn't accessible via Article instances # Bulk delete test: How many objects before and after the delete? >>> Article.objects.all() -[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Fourth article>, <Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>] +[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Article 6>, <Article: Default headline>, <Article: Fourth article>, <Article: Article 7>, <Article: Updated article 8>] >>> Article.objects.filter(id__lte=4).delete() >>> Article.objects.all() [<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>] diff --git a/tests/modeltests/custom_columns/models.py b/tests/modeltests/custom_columns/models.py index e88fa80da2..c09ca05557 100644 --- a/tests/modeltests/custom_columns/models.py +++ b/tests/modeltests/custom_columns/models.py @@ -1,53 +1,105 @@ """ -17. Custom column names +17. Custom column/table names If your database column name is different than your model attribute, use the ``db_column`` parameter. Note that you'll use the field's name, not its column name, in API usage. + +If your database table name is different than your model name, use the +``db_table`` Meta attribute. This has no effect on the API used to +query the database. + +If you need to use a table name for a many-to-many relationship that differs +from the default generated name, use the ``db_table`` parameter on the +ManyToMany field. This has no effect on the API for querying the database. + """ from django.db import models -class Person(models.Model): +class Author(models.Model): first_name = models.CharField(maxlength=30, db_column='firstname') last_name = models.CharField(maxlength=30, db_column='last') def __str__(self): return '%s %s' % (self.first_name, self.last_name) + class Meta: + db_table = 'my_author_table' + ordering = ('last_name','first_name') + +class Article(models.Model): + headline = models.CharField(maxlength=100) + authors = models.ManyToManyField(Author, db_table='my_m2m_table') + + def __str__(self): + return self.headline + + class Meta: + ordering = ('headline',) + __test__ = {'API_TESTS':""" -# Create a Person. ->>> p = Person(first_name='John', last_name='Smith') ->>> p.save() +# Create a Author. +>>> a = Author(first_name='John', last_name='Smith') +>>> a.save() ->>> p.id +>>> a.id 1 ->>> Person.objects.all() -[<Person: John Smith>] +# Create another author +>>> a2 = Author(first_name='Peter', last_name='Jones') +>>> a2.save() + +# Create an article +>>> art = Article(headline='Django lets you build web apps easily') +>>> art.save() +>>> art.authors = [a, a2] ->>> Person.objects.filter(first_name__exact='John') -[<Person: John Smith>] +# Although the table and column names on Author have been set to +# custom values, nothing about using the Author model has changed... ->>> Person.objects.get(first_name__exact='John') -<Person: John Smith> +# Query the available authors +>>> Author.objects.all() +[<Author: Peter Jones>, <Author: John Smith>] ->>> Person.objects.filter(firstname__exact='John') +>>> Author.objects.filter(first_name__exact='John') +[<Author: John Smith>] + +>>> Author.objects.get(first_name__exact='John') +<Author: John Smith> + +>>> Author.objects.filter(firstname__exact='John') Traceback (most recent call last): ... TypeError: Cannot resolve keyword 'firstname' into field ->>> p = Person.objects.get(last_name__exact='Smith') ->>> p.first_name +>>> a = Author.objects.get(last_name__exact='Smith') +>>> a.first_name 'John' ->>> p.last_name +>>> a.last_name 'Smith' ->>> p.firstname +>>> a.firstname Traceback (most recent call last): ... -AttributeError: 'Person' object has no attribute 'firstname' ->>> p.last +AttributeError: 'Author' object has no attribute 'firstname' +>>> a.last Traceback (most recent call last): ... -AttributeError: 'Person' object has no attribute 'last' +AttributeError: 'Author' object has no attribute 'last' + +# Although the Article table uses a custom m2m table, +# nothing about using the m2m relationship has changed... + +# Get all the authors for an article +>>> art.authors.all() +[<Author: Peter Jones>, <Author: John Smith>] + +# Get the articles for an author +>>> a.article_set.all() +[<Article: Django lets you build web apps easily>] + +# Query the authors across the m2m relation +>>> art.authors.filter(last_name='Jones') +[<Author: Peter Jones>] + """} diff --git a/tests/modeltests/generic_relations/models.py b/tests/modeltests/generic_relations/models.py index eb64d7ec3d..2bfb55e618 100644 --- a/tests/modeltests/generic_relations/models.py +++ b/tests/modeltests/generic_relations/models.py @@ -65,14 +65,14 @@ __test__ = {'API_TESTS':""" # Objects with declared GenericRelations can be tagged directly -- the API # mimics the many-to-many API. ->>> lion.tags.create(tag="yellow") -<TaggedItem: yellow> ->>> lion.tags.create(tag="hairy") -<TaggedItem: hairy> >>> bacon.tags.create(tag="fatty") <TaggedItem: fatty> >>> bacon.tags.create(tag="salty") <TaggedItem: salty> +>>> lion.tags.create(tag="yellow") +<TaggedItem: yellow> +>>> lion.tags.create(tag="hairy") +<TaggedItem: hairy> >>> lion.tags.all() [<TaggedItem: hairy>, <TaggedItem: yellow>] @@ -105,4 +105,30 @@ __test__ = {'API_TESTS':""" [<TaggedItem: shiny>] >>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id) [<TaggedItem: clearish>] + +# If you delete an object with an explicit Generic relation, the related +# objects are deleted when the source object is deleted. +# Original list of tags: +>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] +[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('hairy', <ContentType: animal>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2), ('yellow', <ContentType: animal>, 1)] + +>>> lion.delete() +>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] +[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] + +# If Generic Relation is not explicitly defined, any related objects +# remain after deletion of the source object. +>>> quartz.delete() +>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] +[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] + +# If you delete a tag, the objects using the tag are unaffected +# (other than losing a tag) +>>> tag = TaggedItem.objects.get(id=1) +>>> tag.delete() +>>> bacon.tags.all() +[<TaggedItem: salty>] +>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] +[('clearish', <ContentType: mineral>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] + """} diff --git a/tests/modeltests/get_object_or_404/__init__.py b/tests/modeltests/get_object_or_404/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/modeltests/get_object_or_404/__init__.py diff --git a/tests/modeltests/get_object_or_404/models.py b/tests/modeltests/get_object_or_404/models.py new file mode 100644 index 0000000000..79bcc6f52c --- /dev/null +++ b/tests/modeltests/get_object_or_404/models.py @@ -0,0 +1,86 @@ +""" +34. DB-API Shortcuts + +get_object_or_404 is a shortcut function to be used in view functions for +performing a get() lookup and raising a Http404 exception if a DoesNotExist +exception was rasied during the get() call. + +get_list_or_404 is a shortcut function to be used in view functions for +performing a filter() lookup and raising a Http404 exception if a DoesNotExist +exception was rasied during the filter() call. +""" + +from django.db import models +from django.http import Http404 +from django.shortcuts import get_object_or_404, get_list_or_404 + +class Author(models.Model): + name = models.CharField(maxlength=50) + + def __str__(self): + return self.name + +class ArticleManager(models.Manager): + def get_query_set(self): + return super(ArticleManager, self).get_query_set().filter(authors__name__icontains='sir') + +class Article(models.Model): + authors = models.ManyToManyField(Author) + title = models.CharField(maxlength=50) + objects = models.Manager() + by_a_sir = ArticleManager() + + def __str__(self): + return self.title + +__test__ = {'API_TESTS':""" +# Create some Authors. +>>> a = Author.objects.create(name="Brave Sir Robin") +>>> a.save() +>>> a2 = Author.objects.create(name="Patsy") +>>> a2.save() + +# No Articles yet, so we should get a Http404 error. +>>> get_object_or_404(Article, title="Foo") +Traceback (most recent call last): +... +Http404 + +# Create an Article. +>>> article = Article.objects.create(title="Run away!") +>>> article.authors = [a, a2] +>>> article.save() + +# get_object_or_404 can be passed a Model to query. +>>> get_object_or_404(Article, title__contains="Run") +<Article: Run away!> + +# We can also use the the Article manager through an Author object. +>>> get_object_or_404(a.article_set, title__contains="Run") +<Article: Run away!> + +# No articles containing "Camelot". This should raise a Http404 error. +>>> get_object_or_404(a.article_set, title__contains="Camelot") +Traceback (most recent call last): +... +Http404 + +# Custom managers can be used too. +>>> get_object_or_404(Article.by_a_sir, title="Run away!") +<Article: Run away!> + +# get_list_or_404 can be used to get lists of objects +>>> get_list_or_404(a.article_set, title__icontains='Run') +[<Article: Run away!>] + +# Http404 is returned if the list is empty +>>> get_list_or_404(a.article_set, title__icontains='Shrubbery') +Traceback (most recent call last): +... +Http404 + +# Custom managers can be used too. +>>> get_list_or_404(Article.by_a_sir, title__icontains="Run") +[<Article: Run away!>] + +"""} diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py index 09c3aa7aa8..aa903d1a64 100644 --- a/tests/modeltests/lookup/models.py +++ b/tests/modeltests/lookup/models.py @@ -191,4 +191,19 @@ DoesNotExist: Article matching query does not exist. >>> Article.objects.filter(headline__contains='\\') [<Article: Article with \ backslash>] +# none() returns an EmptyQuerySet that behaves like any other QuerySet object +>>> Article.objects.none() +[] +>>> Article.objects.none().filter(headline__startswith='Article') +[] +>>> Article.objects.none().count() +0 + +# using __in with an empty list should return an empty query set +>>> Article.objects.filter(id__in=[]) +[] + +>>> Article.objects.exclude(id__in=[]) +[<Article: Article with \ backslash>, <Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] + """} diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py index 357f3ca629..5e46ad428d 100644 --- a/tests/modeltests/many_to_many/models.py +++ b/tests/modeltests/many_to_many/models.py @@ -203,7 +203,19 @@ __test__ = {'API_TESTS':""" >>> p2.article_set.all() [<Article: Oxygen-free diet works wonders>] -# Recreate the article and Publication we just deleted. +# Relation sets can also be set using primary key values +>>> p2.article_set = [a4.id, a5.id] +>>> p2.article_set.all() +[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>] +>>> a4.publications.all() +[<Publication: Science News>] +>>> a4.publications = [p3.id] +>>> p2.article_set.all() +[<Article: Oxygen-free diet works wonders>] +>>> a4.publications.all() +[<Publication: Science Weekly>] + +# Recreate the article and Publication we have deleted. >>> p1 = Publication(id=None, title='The Python Journal') >>> p1.save() >>> a2 = Article(id=None, headline='NASA uses Python') @@ -231,4 +243,16 @@ __test__ = {'API_TESTS':""" >>> p1.article_set.all() [<Article: NASA uses Python>] +# An alternate to calling clear() is to assign the empty set +>>> p1.article_set = [] +>>> p1.article_set.all() +[] + +>>> a2.publications = [p1, new_publication] +>>> a2.publications.all() +[<Publication: Highlights for Children>, <Publication: The Python Journal>] +>>> a2.publications = [] +>>> a2.publications.all() +[] + """} diff --git a/tests/modeltests/model_forms/__init__.py b/tests/modeltests/model_forms/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/modeltests/model_forms/__init__.py diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py new file mode 100644 index 0000000000..657d506b33 --- /dev/null +++ b/tests/modeltests/model_forms/models.py @@ -0,0 +1,284 @@ +""" +34. Generating HTML forms from models + +Django provides shortcuts for creating Form objects from a model class and a +model instance. + +The function django.newforms.form_for_model() takes a model class and returns +a Form that is tied to the model. This Form works just like any other Form, +with one additional method: save(). The save() method creates an instance +of the model and returns that newly created instance. It saves the instance to +the database if save(commit=True), which is default. If you pass +commit=False, then you'll get the object without committing the changes to the +database. + +The function django.newforms.form_for_instance() takes a model instance and +returns a Form that is tied to the instance. This form works just like any +other Form, with one additional method: save(). The save() +method updates the model instance. It also takes a commit=True parameter. + +The function django.newforms.save_instance() takes a bound form instance and a +model instance and saves the form's clean_data into the instance. It also takes +a commit=True parameter. +""" + +from django.db import models + +class Category(models.Model): + name = models.CharField(maxlength=20) + url = models.CharField('The URL', maxlength=40) + + def __str__(self): + return self.name + +class Writer(models.Model): + name = models.CharField(maxlength=50, help_text='Use both first and last names.') + + def __str__(self): + return self.name + +class Article(models.Model): + headline = models.CharField(maxlength=50) + pub_date = models.DateField() + writer = models.ForeignKey(Writer) + article = models.TextField() + categories = models.ManyToManyField(Category, blank=True) + + def __str__(self): + return self.headline + +__test__ = {'API_TESTS': """ +>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField +>>> import datetime + +>>> Category.objects.all() +[] + +>>> CategoryForm = form_for_model(Category) +>>> f = CategoryForm() +>>> print f +<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr> +<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr> +>>> print f.as_ul() +<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" maxlength="20" /></li> +<li><label for="id_url">The URL:</label> <input id="id_url" type="text" name="url" maxlength="40" /></li> +>>> print f['name'] +<input id="id_name" type="text" name="name" maxlength="20" /> + +>>> f = CategoryForm(auto_id=False) +>>> print f.as_ul() +<li>Name: <input type="text" name="name" maxlength="20" /></li> +<li>The URL: <input type="text" name="url" maxlength="40" /></li> + +>>> f = CategoryForm({'name': 'Entertainment', 'url': 'entertainment'}) +>>> f.is_valid() +True +>>> f.clean_data +{'url': u'entertainment', 'name': u'Entertainment'} +>>> obj = f.save() +>>> obj +<Category: Entertainment> +>>> Category.objects.all() +[<Category: Entertainment>] + +>>> f = CategoryForm({'name': "It's a test", 'url': 'test'}) +>>> f.is_valid() +True +>>> f.clean_data +{'url': u'test', 'name': u"It's a test"} +>>> obj = f.save() +>>> obj +<Category: It's a test> +>>> Category.objects.all() +[<Category: Entertainment>, <Category: It's a test>] + +If you call save() with commit=False, then it will return an object that +hasn't yet been saved to the database. In this case, it's up to you to call +save() on the resulting model instance. +>>> f = CategoryForm({'name': 'Third test', 'url': 'third'}) +>>> f.is_valid() +True +>>> f.clean_data +{'url': u'third', 'name': u'Third test'} +>>> obj = f.save(commit=False) +>>> obj +<Category: Third test> +>>> Category.objects.all() +[<Category: Entertainment>, <Category: It's a test>] +>>> obj.save() +>>> Category.objects.all() +[<Category: Entertainment>, <Category: It's a test>, <Category: Third test>] + +If you call save() with invalid data, you'll get a ValueError. +>>> f = CategoryForm({'name': '', 'url': 'foo'}) +>>> f.errors +{'name': [u'This field is required.']} +>>> f.clean_data +Traceback (most recent call last): +... +AttributeError: 'CategoryForm' object has no attribute 'clean_data' +>>> f.save() +Traceback (most recent call last): +... +ValueError: The Category could not be created because the data didn't validate. +>>> f = CategoryForm({'name': '', 'url': 'foo'}) +>>> f.save() +Traceback (most recent call last): +... +ValueError: The Category could not be created because the data didn't validate. + +Create a couple of Writers. +>>> w = Writer(name='Mike Royko') +>>> w.save() +>>> w = Writer(name='Bob Woodward') +>>> w.save() + +ManyToManyFields are represented by a MultipleChoiceField, and ForeignKeys are +represented by a ChoiceField. +>>> ArticleForm = form_for_model(Article) +>>> f = ArticleForm(auto_id=False) +>>> print f +<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> +<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> +<tr><th>Writer:</th><td><select name="writer"> +<option value="" selected="selected">---------</option> +<option value="1">Mike Royko</option> +<option value="2">Bob Woodward</option> +</select></td></tr> +<tr><th>Article:</th><td><textarea name="article"></textarea></td></tr> +<tr><th>Categories:</th><td><select multiple="multiple" name="categories"> +<option value="1">Entertainment</option> +<option value="2">It's a test</option> +<option value="3">Third test</option> +</select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr> + +You can pass a custom Form class to form_for_model. Make sure it's a +subclass of BaseForm, not Form. +>>> class CustomForm(BaseForm): +... def say_hello(self): +... print 'hello' +>>> CategoryForm = form_for_model(Category, form=CustomForm) +>>> f = CategoryForm() +>>> f.say_hello() +hello + +Use form_for_instance to create a Form from a model instance. The difference +between this Form and one created via form_for_model is that the object's +current values are inserted as 'initial' data in each Field. +>>> w = Writer.objects.get(name='Mike Royko') +>>> RoykoForm = form_for_instance(w) +>>> f = RoykoForm(auto_id=False) +>>> print f +<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr> + +>>> art = Article(headline='Test article', pub_date=datetime.date(1988, 1, 4), writer=w, article='Hello.') +>>> art.save() +>>> art.id +1 +>>> TestArticleForm = form_for_instance(art) +>>> f = TestArticleForm(auto_id=False) +>>> print f.as_ul() +<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li> +<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> +<li>Writer: <select name="writer"> +<option value="">---------</option> +<option value="1" selected="selected">Mike Royko</option> +<option value="2">Bob Woodward</option> +</select></li> +<li>Article: <textarea name="article">Hello.</textarea></li> +<li>Categories: <select multiple="multiple" name="categories"> +<option value="1">Entertainment</option> +<option value="2">It's a test</option> +<option value="3">Third test</option> +</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> +>>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 'writer': u'1', 'article': 'Hello.'}) +>>> f.is_valid() +True +>>> new_art = f.save() +>>> new_art.id +1 +>>> new_art = Article.objects.get(id=1) +>>> new_art.headline +'New headline' + +Add some categories and test the many-to-many form output. +>>> new_art.categories.all() +[] +>>> new_art.categories.add(Category.objects.get(name='Entertainment')) +>>> new_art.categories.all() +[<Category: Entertainment>] +>>> TestArticleForm = form_for_instance(new_art) +>>> f = TestArticleForm(auto_id=False) +>>> print f.as_ul() +<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> +<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> +<li>Writer: <select name="writer"> +<option value="">---------</option> +<option value="1" selected="selected">Mike Royko</option> +<option value="2">Bob Woodward</option> +</select></li> +<li>Article: <textarea name="article">Hello.</textarea></li> +<li>Categories: <select multiple="multiple" name="categories"> +<option value="1" selected="selected">Entertainment</option> +<option value="2">It's a test</option> +<option value="3">Third test</option> +</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> + +>>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', +... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}) +>>> new_art = f.save() +>>> new_art.id +1 +>>> new_art = Article.objects.get(id=1) +>>> new_art.categories.all() +[<Category: Entertainment>, <Category: It's a test>] + +Now, submit form data with no categories. This deletes the existing categories. +>>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', +... 'writer': u'1', 'article': u'Hello.'}) +>>> new_art = f.save() +>>> new_art.id +1 +>>> new_art = Article.objects.get(id=1) +>>> new_art.categories.all() +[] + +Create a new article, with categories, via the form. +>>> ArticleForm = form_for_model(Article) +>>> f = ArticleForm({'headline': u'The walrus was Paul', 'pub_date': u'1967-11-01', +... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) +>>> new_art = f.save() +>>> new_art.id +2 +>>> new_art = Article.objects.get(id=2) +>>> new_art.categories.all() +[<Category: Entertainment>, <Category: It's a test>] + +Create a new article, with no categories, via the form. +>>> ArticleForm = form_for_model(Article) +>>> f = ArticleForm({'headline': u'The walrus was Paul', 'pub_date': u'1967-11-01', +... 'writer': u'1', 'article': u'Test.'}) +>>> new_art = f.save() +>>> new_art.id +3 +>>> new_art = Article.objects.get(id=3) +>>> new_art.categories.all() +[] + +Here, we define a custom Form. Because it happens to have the same fields as +the Category model, we can use save_instance() to apply its changes to an +existing Category instance. +>>> class ShortCategory(Form): +... name = CharField(max_length=5) +... url = CharField(max_length=3) +>>> cat = Category.objects.get(name='Third test') +>>> cat +<Category: Third test> +>>> cat.id +3 +>>> sc = ShortCategory({'name': 'Third', 'url': '3rd'}) +>>> save_instance(sc, cat) +<Category: Third> +>>> Category.objects.get(id=3) +<Category: Third> +"""} diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py index 2de18edc1f..9f926a7373 100644 --- a/tests/modeltests/or_lookups/models.py +++ b/tests/modeltests/or_lookups/models.py @@ -69,6 +69,21 @@ __test__ = {'API_TESTS':""" >>> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3)) [<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] +# You could also use "in" to accomplish the same as above. +>>> Article.objects.filter(pk__in=[1,2,3]) +[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] + +>>> Article.objects.filter(pk__in=[1,2,3,4]) +[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] + +# Passing "in" an empty list returns no results ... +>>> Article.objects.filter(pk__in=[]) +[] + +# ... but can return results if we OR it with another query. +>>> Article.objects.filter(Q(pk__in=[]) | Q(headline__icontains='goodbye')) +[<Article: Goodbye>, <Article: Hello and goodbye>] + # Q arg objects are ANDed >>> Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')) [<Article: Hello and goodbye>] diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py index d1d10b43c0..e24ff537c1 100644 --- a/tests/modeltests/serializers/models.py +++ b/tests/modeltests/serializers/models.py @@ -37,6 +37,13 @@ class Article(models.Model): def __str__(self): return self.headline +class AuthorProfile(models.Model): + author = models.OneToOneField(Author) + date_of_birth = models.DateField() + + def __str__(self): + return "Profile of %s" % self.author + __test__ = {'API_TESTS':""" # Create some data: >>> from datetime import datetime @@ -118,4 +125,18 @@ __test__ = {'API_TESTS':""" >>> Article.objects.all() [<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>] +# If you use your own primary key field (such as a OneToOneField), +# it doesn't appear in the serialized field list - it replaces the +# pk identifier. +>>> profile = AuthorProfile(author=joe, date_of_birth=datetime(1970,1,1)) +>>> profile.save() + +>>> json = serializers.serialize("json", AuthorProfile.objects.all()) +>>> json +'[{"pk": "1", "model": "serializers.authorprofile", "fields": {"date_of_birth": "1970-01-01"}}]' + +>>> for obj in serializers.deserialize("json", json): +... print obj +<DeserializedObject: Profile of Joe> + """} diff --git a/tests/modeltests/test_client/views.py b/tests/modeltests/test_client/views.py index bf131032eb..7acfc2db60 100644 --- a/tests/modeltests/test_client/views.py +++ b/tests/modeltests/test_client/views.py @@ -26,10 +26,10 @@ def redirect_view(request): "A view that redirects all requests to the GET view" return HttpResponseRedirect('/test_client/get_view/') -@login_required def login_protected_view(request): "A simple view that is login protected." t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template') c = Context({'user': request.user}) return HttpResponse(t.render(c)) +login_protected_view = login_required(login_protected_view)
\ No newline at end of file |
