Changeset 5488 for django/branches/per-object-permissions/tests/modeltests
- Timestamp:
- 06/17/07 17:18:54 (2 years ago)
- Files:
-
- django/branches/per-object-permissions/tests/modeltests/basic/models.py (modified) (3 diffs)
- django/branches/per-object-permissions/tests/modeltests/custom_columns/models.py (modified) (2 diffs)
- django/branches/per-object-permissions/tests/modeltests/empty/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/field_defaults/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/fixtures (copied) (copied from django/trunk/tests/modeltests/fixtures)
- django/branches/per-object-permissions/tests/modeltests/fixtures/fixtures (copied) (copied from django/trunk/tests/modeltests/fixtures/fixtures)
- django/branches/per-object-permissions/tests/modeltests/fixtures/fixtures/fixture1.json (copied) (copied from django/trunk/tests/modeltests/fixtures/fixtures/fixture1.json)
- django/branches/per-object-permissions/tests/modeltests/fixtures/fixtures/fixture2.json (copied) (copied from django/trunk/tests/modeltests/fixtures/fixtures/fixture2.json)
- django/branches/per-object-permissions/tests/modeltests/fixtures/fixtures/fixture2.xml (copied) (copied from django/trunk/tests/modeltests/fixtures/fixtures/fixture2.xml)
- django/branches/per-object-permissions/tests/modeltests/fixtures/fixtures/fixture3.xml (copied) (copied from django/trunk/tests/modeltests/fixtures/fixtures/fixture3.xml)
- django/branches/per-object-permissions/tests/modeltests/fixtures/fixtures/initial_data.json (copied) (copied from django/trunk/tests/modeltests/fixtures/fixtures/initial_data.json)
- django/branches/per-object-permissions/tests/modeltests/fixtures/__init__.py (copied) (copied from django/trunk/tests/modeltests/fixtures/__init__.py)
- django/branches/per-object-permissions/tests/modeltests/fixtures/models.py (copied) (copied from django/trunk/tests/modeltests/fixtures/models.py)
- django/branches/per-object-permissions/tests/modeltests/generic_relations/models.py (modified) (7 diffs)
- django/branches/per-object-permissions/tests/modeltests/get_object_or_404 (copied) (copied from django/trunk/tests/modeltests/get_object_or_404)
- django/branches/per-object-permissions/tests/modeltests/get_object_or_404/__init__.py (copied) (copied from django/trunk/tests/modeltests/get_object_or_404/__init__.py)
- django/branches/per-object-permissions/tests/modeltests/get_object_or_404/models.py (copied) (copied from django/trunk/tests/modeltests/get_object_or_404/models.py)
- django/branches/per-object-permissions/tests/modeltests/get_or_create/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/invalid_models/models.py (modified) (3 diffs)
- django/branches/per-object-permissions/tests/modeltests/lookup/models.py (modified) (3 diffs)
- django/branches/per-object-permissions/tests/modeltests/m2m_and_m2o/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/m2m_recursive/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/manipulators/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/many_to_many/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/many_to_one/models.py (modified) (2 diffs)
- django/branches/per-object-permissions/tests/modeltests/model_forms/models.py (modified) (7 diffs)
- django/branches/per-object-permissions/tests/modeltests/or_lookups/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/pagination/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/reverse_lookup/models.py (modified) (1 diff)
- django/branches/per-object-permissions/tests/modeltests/select_related (copied) (copied from django/trunk/tests/modeltests/select_related)
- django/branches/per-object-permissions/tests/modeltests/select_related/__init__.py (copied) (copied from django/trunk/tests/modeltests/select_related/__init__.py)
- django/branches/per-object-permissions/tests/modeltests/select_related/models.py (copied) (copied from django/trunk/tests/modeltests/select_related/models.py)
- django/branches/per-object-permissions/tests/modeltests/serializers/models.py (modified) (3 diffs)
- django/branches/per-object-permissions/tests/modeltests/test_client/fixtures (copied) (copied from django/trunk/tests/modeltests/test_client/fixtures)
- django/branches/per-object-permissions/tests/modeltests/test_client/fixtures/testdata.json (copied) (copied from django/trunk/tests/modeltests/test_client/fixtures/testdata.json)
- django/branches/per-object-permissions/tests/modeltests/test_client/management.py (deleted)
- django/branches/per-object-permissions/tests/modeltests/test_client/models.py (modified) (8 diffs)
- django/branches/per-object-permissions/tests/modeltests/test_client/urls.py (modified) (2 diffs)
- django/branches/per-object-permissions/tests/modeltests/test_client/views.py (modified) (3 diffs)
- django/branches/per-object-permissions/tests/modeltests/validation/models.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/per-object-permissions/tests/modeltests/basic/models.py
r4242 r5488 13 13 class Meta: 14 14 ordering = ('pub_date','headline') 15 15 16 16 def __str__(self): 17 17 return self.headline … … 320 320 >>> Article.objects.all() 321 321 [<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>] 322 323 322 """} 324 323 … … 359 358 >>> Article.objects.get(headline="Article 10") 360 359 <Article: Article 10> 361 """ 360 361 # Edge-case test: A year lookup should retrieve all objects in the given 362 year, including Jan. 1 and Dec. 31. 363 >>> a11 = Article.objects.create(headline='Article 11', pub_date=datetime(2008, 1, 1)) 364 >>> a12 = Article.objects.create(headline='Article 12', pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999)) 365 >>> Article.objects.filter(pub_date__year=2008) 366 [<Article: Article 11>, <Article: Article 12>] 367 """ django/branches/per-object-permissions/tests/modeltests/custom_columns/models.py
r3669 r5488 1 1 """ 2 17. Custom column names2 17. Custom column/table names 3 3 4 4 If your database column name is different than your model attribute, use the 5 5 ``db_column`` parameter. Note that you'll use the field's name, not its column 6 6 name, in API usage. 7 8 If your database table name is different than your model name, use the 9 ``db_table`` Meta attribute. This has no effect on the API used to 10 query the database. 11 12 If you need to use a table name for a many-to-many relationship that differs 13 from the default generated name, use the ``db_table`` parameter on the 14 ManyToMany field. This has no effect on the API for querying the database. 15 7 16 """ 8 17 9 18 from django.db import models 10 19 11 class Person(models.Model):20 class Author(models.Model): 12 21 first_name = models.CharField(maxlength=30, db_column='firstname') 13 22 last_name = models.CharField(maxlength=30, db_column='last') … … 16 25 return '%s %s' % (self.first_name, self.last_name) 17 26 27 class Meta: 28 db_table = 'my_author_table' 29 ordering = ('last_name','first_name') 30 31 class Article(models.Model): 32 headline = models.CharField(maxlength=100) 33 authors = models.ManyToManyField(Author, db_table='my_m2m_table') 34 35 def __str__(self): 36 return self.headline 37 38 class Meta: 39 ordering = ('headline',) 40 18 41 __test__ = {'API_TESTS':""" 19 # Create a Person.20 >>> p = Person(first_name='John', last_name='Smith')21 >>> p.save()42 # Create a Author. 43 >>> a = Author(first_name='John', last_name='Smith') 44 >>> a.save() 22 45 23 >>> p.id46 >>> a.id 24 47 1 25 48 26 >>> Person.objects.all() 27 [<Person: John Smith>] 49 # Create another author 50 >>> a2 = Author(first_name='Peter', last_name='Jones') 51 >>> a2.save() 28 52 29 >>> Person.objects.filter(first_name__exact='John') 30 [<Person: John Smith>] 53 # Create an article 54 >>> art = Article(headline='Django lets you build web apps easily') 55 >>> art.save() 56 >>> art.authors = [a, a2] 31 57 32 >>> Person.objects.get(first_name__exact='John') 33 <Person: John Smith> 58 # Although the table and column names on Author have been set to 59 # custom values, nothing about using the Author model has changed... 34 60 35 >>> Person.objects.filter(firstname__exact='John') 61 # Query the available authors 62 >>> Author.objects.all() 63 [<Author: Peter Jones>, <Author: John Smith>] 64 65 >>> Author.objects.filter(first_name__exact='John') 66 [<Author: John Smith>] 67 68 >>> Author.objects.get(first_name__exact='John') 69 <Author: John Smith> 70 71 >>> Author.objects.filter(firstname__exact='John') 36 72 Traceback (most recent call last): 37 73 ... 38 TypeError: Cannot resolve keyword 'firstname' into field 74 TypeError: Cannot resolve keyword 'firstname' into field. Choices are: article, id, first_name, last_name 39 75 40 >>> p = Person.objects.get(last_name__exact='Smith')41 >>> p.first_name76 >>> a = Author.objects.get(last_name__exact='Smith') 77 >>> a.first_name 42 78 'John' 43 >>> p.last_name79 >>> a.last_name 44 80 'Smith' 45 >>> p.firstname81 >>> a.firstname 46 82 Traceback (most recent call last): 47 83 ... 48 AttributeError: ' Person' object has no attribute 'firstname'49 >>> p.last84 AttributeError: 'Author' object has no attribute 'firstname' 85 >>> a.last 50 86 Traceback (most recent call last): 51 87 ... 52 AttributeError: 'Person' object has no attribute 'last' 88 AttributeError: 'Author' object has no attribute 'last' 89 90 # Although the Article table uses a custom m2m table, 91 # nothing about using the m2m relationship has changed... 92 93 # Get all the authors for an article 94 >>> art.authors.all() 95 [<Author: Peter Jones>, <Author: John Smith>] 96 97 # Get the articles for an author 98 >>> a.article_set.all() 99 [<Article: Django lets you build web apps easily>] 100 101 # Query the authors across the m2m relation 102 >>> art.authors.filter(last_name='Jones') 103 [<Author: Peter Jones>] 104 53 105 """} django/branches/per-object-permissions/tests/modeltests/empty/models.py
r3669 r5488 1 1 """ 2 Empty model tests2 39. Empty model tests 3 3 4 4 These test that things behave sensibly for the rare corner-case of a model with django/branches/per-object-permissions/tests/modeltests/field_defaults/models.py
r3669 r5488 1 1 """ 2 3 1. Callable defaults2 32. Callable defaults 3 3 4 4 You can pass callable objects as the ``default`` parameter to a field. When django/branches/per-object-permissions/tests/modeltests/generic_relations/models.py
r3669 r5488 1 1 """ 2 3 3. Generic relations2 34. Generic relations 3 3 4 4 Generic relations let an object have a foreign key to any object through a … … 12 12 from django.db import models 13 13 from django.contrib.contenttypes.models import ContentType 14 from django.contrib.contenttypes import generic 14 15 15 16 class TaggedItem(models.Model): … … 19 20 object_id = models.PositiveIntegerField() 20 21 21 content_object = models.GenericForeignKey()22 content_object = generic.GenericForeignKey() 22 23 23 24 class Meta: … … 31 32 latin_name = models.CharField(maxlength=150) 32 33 33 tags = models.GenericRelation(TaggedItem)34 tags = generic.GenericRelation(TaggedItem) 34 35 35 36 def __str__(self): … … 40 41 is_yucky = models.BooleanField(default=True) 41 42 42 tags = models.GenericRelation(TaggedItem)43 tags = generic.GenericRelation(TaggedItem) 43 44 44 45 def __str__(self): … … 66 67 # Objects with declared GenericRelations can be tagged directly -- the API 67 68 # mimics the many-to-many API. 69 >>> bacon.tags.create(tag="fatty") 70 <TaggedItem: fatty> 71 >>> bacon.tags.create(tag="salty") 72 <TaggedItem: salty> 68 73 >>> lion.tags.create(tag="yellow") 69 74 <TaggedItem: yellow> 70 75 >>> lion.tags.create(tag="hairy") 71 76 <TaggedItem: hairy> 72 >>> bacon.tags.create(tag="fatty")73 <TaggedItem: fatty>74 >>> bacon.tags.create(tag="salty")75 <TaggedItem: salty>76 77 77 78 >>> lion.tags.all() … … 106 107 >>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id) 107 108 [<TaggedItem: clearish>] 109 110 # If you delete an object with an explicit Generic relation, the related 111 # objects are deleted when the source object is deleted. 112 # Original list of tags: 113 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 114 [('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('hairy', <ContentType: animal>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2), ('yellow', <ContentType: animal>, 1)] 115 116 >>> lion.delete() 117 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 118 [('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 119 120 # If Generic Relation is not explicitly defined, any related objects 121 # remain after deletion of the source object. 122 >>> quartz.delete() 123 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 124 [('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 125 126 # If you delete a tag, the objects using the tag are unaffected 127 # (other than losing a tag) 128 >>> tag = TaggedItem.objects.get(id=1) 129 >>> tag.delete() 130 >>> bacon.tags.all() 131 [<TaggedItem: salty>] 132 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 133 [('clearish', <ContentType: mineral>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 134 108 135 """} django/branches/per-object-permissions/tests/modeltests/get_or_create/models.py
r3669 r5488 1 1 """ 2 3 2. get_or_create()2 33. get_or_create() 3 3 4 4 get_or_create() does what it says: it tries to look up an object with the given django/branches/per-object-permissions/tests/modeltests/invalid_models/models.py
r3810 r5488 9 9 class FieldErrors(models.Model): 10 10 charfield = models.CharField() 11 floatfield = models.FloatField()11 decimalfield = models.DecimalField() 12 12 filefield = models.FileField() 13 13 prepopulate = models.CharField(maxlength=10, prepopulate_from='bad') … … 88 88 selfclashm2m = models.CharField(maxlength=10) 89 89 90 # Non-symmetrical M2M fields _do_ have related accessors, so 90 # Non-symmetrical M2M fields _do_ have related accessors, so 91 91 # there is potential for clashes. 92 92 selfclashm2m_set = models.ManyToManyField("SelfClashM2M", symmetrical=False) 93 93 94 94 m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id', symmetrical=False) 95 95 m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe', symmetrical=False) … … 98 98 m2m_4 = models.ManyToManyField('self', symmetrical=False) 99 99 100 class Model(models.Model): 101 "But it's valid to call a model Model." 102 year = models.PositiveIntegerField() #1960 103 make = models.CharField(maxlength=10) #Aston Martin 104 name = models.CharField(maxlength=10) #DB 4 GT 105 106 class Car(models.Model): 107 colour = models.CharField(maxlength=5) 108 model = models.ForeignKey(Model) 109 100 110 model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. 101 invalid_models.fielderrors: " floatfield": FloatFields require a "decimal_places" attribute.102 invalid_models.fielderrors: " floatfield": FloatFields require a "max_digits" attribute.111 invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute. 112 invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute. 103 113 invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute. 104 114 invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple. django/branches/per-object-permissions/tests/modeltests/lookup/models.py
r3669 r5488 59 59 0L 60 60 61 # count() should respect sliced query sets. 62 >>> articles = Article.objects.all() 63 >>> articles.count() 64 7L 65 >>> articles[:4].count() 66 4 67 >>> articles[1:100].count() 68 6L 69 >>> articles[10:100].count() 70 0 71 61 72 # Date and date/time lookups can also be done with strings. 62 73 >>> Article.objects.filter(pub_date__exact='2005-07-27 00:00:00').count() … … 120 131 [('headline', 'Article 7'), ('id', 7)] 121 132 [('headline', 'Article 1'), ('id', 1)] 133 134 135 # you can use values() even on extra fields 136 >>> for d in Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_one'): 137 ... i = d.items() 138 ... i.sort() 139 ... i 140 [('id', 5), ('id_plus_one', 6)] 141 [('id', 6), ('id_plus_one', 7)] 142 [('id', 4), ('id_plus_one', 5)] 143 [('id', 2), ('id_plus_one', 3)] 144 [('id', 3), ('id_plus_one', 4)] 145 [('id', 7), ('id_plus_one', 8)] 146 [('id', 1), ('id_plus_one', 2)] 147 148 # however, an exception FieldDoesNotExist will still be thrown 149 # if you try to access non-existent field (field that is neither on the model nor extra) 150 >>> Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_two') 151 Traceback (most recent call last): 152 ... 153 FieldDoesNotExist: Article has no field named 'id_plus_two' 122 154 123 155 # if you don't specify which fields, all are returned … … 192 224 [<Article: Article with \ backslash>] 193 225 226 # none() returns an EmptyQuerySet that behaves like any other QuerySet object 227 >>> Article.objects.none() 228 [] 229 >>> Article.objects.none().filter(headline__startswith='Article') 230 [] 231 >>> Article.objects.none().count() 232 0 233 >>> [article for article in Article.objects.none().iterator()] 234 [] 235 236 # using __in with an empty list should return an empty query set 237 >>> Article.objects.filter(id__in=[]) 238 [] 239 240 >>> Article.objects.exclude(id__in=[]) 241 [<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>] 242 243 # Programming errors are pointed out with nice error messages 244 >>> Article.objects.filter(pub_date_year='2005').count() 245 Traceback (most recent call last): 246 ... 247 TypeError: Cannot resolve keyword 'pub_date_year' into field. Choices are: id, headline, pub_date 248 249 >>> Article.objects.filter(headline__starts='Article') 250 Traceback (most recent call last): 251 ... 252 TypeError: Cannot resolve keyword 'headline__starts' into field. Choices are: id, headline, pub_date 253 194 254 """} django/branches/per-object-permissions/tests/modeltests/m2m_and_m2o/models.py
r3669 r5488 1 1 """ 2 2 8. Many-to-many and many-to-one relationships to the same table2 29. Many-to-many and many-to-one relationships to the same table 3 3 4 4 Make sure to set ``related_name`` if you use relationships to the same table. django/branches/per-object-permissions/tests/modeltests/m2m_recursive/models.py
r3669 r5488 1 1 """ 2 2 7. Many-to-many relationships between the same two tables2 28. Many-to-many relationships between the same two tables 3 3 4 4 In this example, A Person can have many friends, who are also people. Friendship is a django/branches/per-object-permissions/tests/modeltests/manipulators/models.py
r3669 r5488 1 1 """ 2 2 6. Default manipulators2 27. Default manipulators 3 3 4 4 Each model gets an AddManipulator and ChangeManipulator by default. django/branches/per-object-permissions/tests/modeltests/many_to_many/models.py
r4242 r5488 204 204 [<Article: Oxygen-free diet works wonders>] 205 205 206 # Recreate the article and Publication we just deleted. 206 # Relation sets can also be set using primary key values 207 >>> p2.article_set = [a4.id, a5.id] 208 >>> p2.article_set.all() 209 [<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>] 210 >>> a4.publications.all() 211 [<Publication: Science News>] 212 >>> a4.publications = [p3.id] 213 >>> p2.article_set.all() 214 [<Article: Oxygen-free diet works wonders>] 215 >>> a4.publications.all() 216 [<Publication: Science Weekly>] 217 218 # Recreate the article and Publication we have deleted. 207 219 >>> p1 = Publication(id=None, title='The Python Journal') 208 220 >>> p1.save() django/branches/per-object-permissions/tests/modeltests/many_to_one/models.py
r3669 r5488 175 175 Traceback (most recent call last): 176 176 ... 177 TypeError: Cannot resolve keyword 'reporter_id' into field 177 TypeError: Cannot resolve keyword 'reporter_id' into field. Choices are: id, headline, pub_date, reporter 178 178 179 179 # You need to specify a comparison clause … … 181 181 Traceback (most recent call last): 182 182 ... 183 TypeError: Cannot resolve keyword 'reporter_id' into field 183 TypeError: Cannot resolve keyword 'reporter_id' into field. Choices are: id, headline, pub_date, reporter 184 184 185 185 # You can also instantiate an Article by passing django/branches/per-object-permissions/tests/modeltests/model_forms/models.py
r4242 r5488 1 1 """ 2 34. Generating HTML forms from models 3 4 Django provides shortcuts for creating Form objects from a model class. 2 36. Generating HTML forms from models 3 4 Django provides shortcuts for creating Form objects from a model class and a 5 model instance. 5 6 6 7 The function django.newforms.form_for_model() takes a model class and returns 7 8 a Form that is tied to the model. This Form works just like any other Form, 8 with one additional method: create(). The create() method creates an instance9 with one additional method: save(). The save() method creates an instance 9 10 of the model and returns that newly created instance. It saves the instance to 10 the database if create(save=True), which is default. If you pass 11 create(save=False), then you'll get the object without saving it. 11 the database if save(commit=True), which is default. If you pass 12 commit=False, then you'll get the object without committing the changes to the 13 database. 14 15 The function django.newforms.form_for_instance() takes a model instance and 16 returns a Form that is tied to the instance. This form works just like any 17 other Form, with one additional method: save(). The save() 18 method updates the model instance. It also takes a commit=True parameter. 19 20 The function django.newforms.save_instance() takes a bound form instance and a 21 model instance and saves the form's cleaned_data into the instance. It also takes 22 a commit=True parameter. 12 23 """ 13 24 14 25 from django.db import models 26 27 ARTICLE_STATUS = ( 28 (1, 'Draft'), 29 (2, 'Pending'), 30 (3, 'Live'), 31 ) 15 32 16 33 class Category(models.Model): … … 21 38 return self.name 22 39 40 class Writer(models.Model): 41 name = models.CharField(maxlength=50, help_text='Use both first and last names.') 42 43 def __str__(self): 44 return self.name 45 23 46 class Article(models.Model): 24 47 headline = models.CharField(maxlength=50) 25 pub_date = models.DateTimeField() 26 categories = models.ManyToManyField(Category) 48 pub_date = models.DateField() 49 created = models.DateField(editable=False) 50 writer = models.ForeignKey(Writer) 51 article = models.TextField() 52 categories = models.ManyToManyField(Category, blank=True) 53 status = models.IntegerField(choices=ARTICLE_STATUS, blank=True, null=True) 54 55 def save(self): 56 import datetime 57 if not self.id: 58 self.created = datetime.date.today() 59 return super(Article, self).save() 27 60 28 61 def __str__(self): 29 62 return self.headline 30 63 64 class PhoneNumber(models.Model): 65 phone = models.PhoneNumberField() 66 description = models.CharField(maxlength=20) 67 68 def __str__(self): 69 return self.phone 70 31 71 __test__ = {'API_TESTS': """ 32 >>> from django.newforms import form_for_model, BaseForm 72 >>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField 73 >>> import datetime 33 74 34 75 >>> Category.objects.all() … … 52 93 53 94 >>> f = CategoryForm({'name': 'Entertainment', 'url': 'entertainment'}) 54 >>> f. errors55 {} 56 >>> f.clean _data95 >>> f.is_valid() 96 True 97 >>> f.cleaned_data 57 98 {'url': u'entertainment', 'name': u'Entertainment'} 58 >>> obj = f. create()99 >>> obj = f.save() 59 100 >>> obj 60 101 <Category: Entertainment> … … 63 104 64 105 >>> f = CategoryForm({'name': "It's a test", 'url': 'test'}) 65 >>> f. errors66 {} 67 >>> f.clean _data106 >>> f.is_valid() 107 True 108 >>> f.cleaned_data 68 109 {'url': u'test', 'name': u"It's a test"} 69 >>> obj = f. create()110 >>> obj = f.save() 70 111 >>> obj 71 112 <Category: It's a test> … … 73 114 [<Category: Entertainment>, <Category: It's a test>] 74 115 116 If you call save() with commit=False, then it will return an object that 117 hasn't yet been saved to the database. In this case, it's up to you to call 118 save() on the resulting model instance. 75 119 >>> f = CategoryForm({'name': 'Third test', 'url': 'third'}) 76 >>> f. errors77 {} 78 >>> f.clean _data120 >>> f.is_valid() 121 True 122 >>> f.cleaned_data 79 123 {'url': u'third', 'name': u'Third test'} 80 >>> obj = f. create(save=False)124 >>> obj = f.save(commit=False) 81 125 >>> obj 82 126 <Category: Third test> … … 87 131 [<Category: Entertainment>, <Category: It's a test>, <Category: Third test>] 88 132 133 If you call save() with invalid data, you'll get a ValueError. 89 134 >>> f = CategoryForm({'name': '', 'url': 'foo'}) 90 135 >>> f.errors 91 136 {'name': [u'This field is required.']} 92 >>> f.clean_data 93 >>> f.create() 137 >>> f.cleaned_data 138 Traceback (most recent call last): 139 ... 140 AttributeError: 'CategoryForm' object has no attribute 'cleaned_data' 141 >>> f.save() 94 142 Traceback (most recent call last): 95 143 ... 96 144 ValueError: The Category could not be created because the data didn't validate. 97 98 145 >>> f = CategoryForm({'name': '', 'url': 'foo'}) 99 >>> f. create()146 >>> f.save() 100 147 Traceback (most recent call last): 101 148 ... 102 149 ValueError: The Category could not be created because the data didn't validate. 150 151 Create a couple of Writers. 152 >>> w = Writer(name='Mike Royko') 153 >>> w.save() 154 >>> w = Writer(name='Bob Woodward') 155 >>> w.save() 156 157 ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any 158 fields with the 'choices' attribute are represented by a ChoiceField. 159 >>> ArticleForm = form_for_model(Article) 160 >>> f = ArticleForm(auto_id=False) 161 >>> print f 162 <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> 163 <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> 164 <tr><th>Writer:</th><td><select name="writer"> 165 <option value="" selected="selected">---------</option> 166 <option value="1">Mike Royko</option> 167 <option value="2">Bob Woodward</option> 168 </select></td></tr> 169 <tr><th>Article:</th><td><textarea rows="10" cols="40" name="article"></textarea></td></tr> 170 <tr><th>Status:</th><td><select name="status"> 171 <option value="" selected="selected">---------</option> 172 <option value="1">Draft</option> 173 <option value="2">Pending</option> 174 <option value="3">Live</option> 175 </select></td></tr> 176 <tr><th>Categories:</th><td><select multiple="multiple" name="categories"> 177 <option value="1">Entertainment</option> 178 <option value="2">It's a test</option> 179 <option value="3">Third test</option> 180 </select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr> 181 182 You can restrict a form to a subset of the complete list of fields 183 by providing a 'fields' argument. If you try to save a 184 model created with such a form, you need to ensure that the fields 185 that are _not_ on the form have default values, or are allowed to have 186 a value of None. If a field isn't specified on a form, the object created 187 from the form can't provide a value for that field! 188 >>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date')) 189 >>> f = PartialArticleForm(auto_id=False) 190 >>> print f 191 <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> 192 <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> 103 193 104 194 You can pass a custom Form class to form_for_model. Make sure it's a … … 111 201 >>> f.say_hello() 112 202 hello 203 204 Use form_for_instance to create a Form from a model instance. The difference 205 between this Form and one created via form_for_model is that the object's 206 current values are inserted as 'initial' data in each Field. 207 >>> w = Writer.objects.get(name='Mike Royko') 208 >>> RoykoForm = form_for_instance(w) 209 >>> f = RoykoForm(auto_id=False) 210 >>> print f 211 <tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr> 212 213 >>> art = Article(headline='Test article', pub_date=datetime.date(1988, 1, 4), writer=w, article='Hello.') 214 >>> art.save() 215 >>> art.id 216 1 217 >>> TestArticleForm = form_for_instance(art) 218 >>> f = TestArticleForm(auto_id=False) 219 >>> print f.as_ul() 220 <li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li> 221 <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> 222 <li>Writer: <select name="writer"> 223 <option value="">---------</option> 224 <option value="1" selected="selected">Mike Royko</option> 225 <option value="2">Bob Woodward</option> 226 </select></li> 227 <li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li> 228 <li>Status: <select name="status"> 229 <option value="" selected="selected">---------</option> 230 <option value="1">Draft</option> 231 <option value="2">Pending</option> 232 <option value="3">Live</option> 233 </select></li> 234 <li>Categories: <select multiple="multiple" name="categories"> 235 <option value="1">Entertainment</option> 236 <option value="2">It's a test</option> 237 <option value="3">Third test</option> 238 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> 239 >>> f = TestArticleForm({'headline': u'Test headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}) 240 >>> f.is_valid() 241 True 242 >>> test_art = f.save() 243 >>> test_art.id 244 1 245 >>> test_art = Article.objects.get(id=1) 246 >>> test_art.headline 247 'Test headline' 248 249 You can create a form over a subset of the available fields 250 by specifying a 'fields' argument to form_for_instance. 251 >>> PartialArticleForm = form_for_instance(art, fields=('headline','pub_date')) 252 >>> f = PartialArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04'}, auto_id=False) 253 >>> print f.as_ul() 254 <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> 255 <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> 256 >>> f.is_valid() 257 True 258 >>> new_art = f.save() 259 >>> new_art.id 260 1 261 >>> new_art = Article.objects.get(id=1) 262 >>> new_art.headline 263 'New headline' 264 265 Add some categories and test the many-to-many form output. 266 >>> new_art.categories.all() 267 [] 268 >>> new_art.categories.add(Category.objects.get(name='Entertainment')) 269 >>> new_art.categories.all() 270 [<Category: Entertainment>] 271 >>> TestArticleForm = form_for_instance(new_art) 272 >>> f = TestArticleForm(auto_id=False) 273 >>> print f.as_ul() 274 <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> 275 <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> 276 <li>Writer: <select name="writer"> 277 <option value="">---------</option> 278 <option value="1" selected="selected">Mike Royko</option> 279 <option value="2">Bob Woodward</option> 280 </select></li> 281 <li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li> 282 <li>Status: <select name="status"> 283 <option value="" selected="selected">---------</option> 284 <option value="1">Draft</option> 285 <option value="2">Pending</option> 286 <option value="3">Live</option> 287 </select></li> 288 <li>Categories: <select multiple="multiple" name="categories"> 289 <option value="1" selected="selected">Entertainment</option> 290 <option value="2">It's a test</option> 291 <option value="3">Third test</option> 292 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> 293 294 >>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 295 ... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}) 296 >>> new_art = f.save() 297 >>> new_art.id 298 1 299 >>> new_art = Article.objects.get(id=1) 300 >>> new_art.categories.all() 301 [<Category: Entertainment>, <Category: It's a test>] 302 303 Now, submit form data with no categories. This deletes the existing categories. 304 >>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 305 ... 'writer': u'1', 'article': u'Hello.'}) 306 >>> new_art = f.save() 307 >>> new_art.id 308 1 309 >>> new_art = Article.objects.get(id=1) 310 >>> new_art.categories.all() 311 [] 312 313 Create a new article, with categories, via the form. 314 >>> ArticleForm = form_for_model(Article) 315 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'pub_date': u'1967-11-01', 316 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 317 >>> new_art = f.save() 318 >>> new_art.id 319 2 320 >>> new_art = Article.objects.get(id=2) 321 >>> new_art.categories.all() 322 [<Category: Entertainment>, <Category: It's a test>] 323 324 Create a new article, with no categories, via the form. 325 >>> ArticleForm = form_for_model(Article) 326 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'pub_date': u'1967-11-01', 327 ... 'writer': u'1', 'article': u'Test.'}) 328 >>> new_art = f.save() 329 >>> new_art.id 330 3 331 >>> new_art = Article.objects.get(id=3) 332 >>> new_art.categories.all() 333 [] 334 335 Here, we define a custom Form. Because it happens to have the same fields as 336 the Category model, we can use save_instance() to apply its changes to an 337 existing Category instance. 338 >>> class ShortCategory(Form): 339 ... name = CharField(max_length=5) 340 ... url = CharField(max_length=3) 341 >>> cat = Category.objects.get(name='Third test') 342 >>> cat 343 <Category: Third test> 344 >>> cat.id 345 3 346 >>> sc = ShortCategory({'name': 'Third', 'url': '3rd'}) 347 >>> save_instance(sc, cat) 348 <Category: Third> 349 >>> Category.objects.get(id=3) 350 <Category: Third> 351 352 Here, we demonstrate that choices for a ForeignKey ChoiceField are determined 353 at runtime, based on the data in the database when the form is displayed, not 354 the data in the database when the form is instantiated. 355 >>> ArticleForm = form_for_model(Article) 356 >>> f = ArticleForm(auto_id=False) 357 >>> print f.as_ul()
