# Bare-bones model # This is a basic model with only two non-primary-key fields. require 'test/helper' class Article < Model has :headline, CharField(:maxlength=>100, :default=>'Default headline') has :pub_date, DateTimeField() ordered_by :pub_date,:headline def to_s headline end end DocTest.new Util.install_database __END__ FIXME: code is still intertwingled with old Python, from django's tests. Well, just ignore it. No articles are in the system yet. >> Article.all => [] Create an Article. >> a = Article.new(:headline=>'DBZ is kewl', :pub_date=>Time.gm(2007, 7, 28)) => #
Save it into the database. You have to call save() explicitly. >> a.save => #
Now it has an ID. >> a.id => 1 Access database columns via normal methods. >> a.headline => "DBZ is kewl" >> a.pub_date => Sat Jul 28 00:00:00 UTC 2007 Change values by changing the attributes, then calling save(). >> a.headline = 'django & rails are nice too' => "django & rails are nice too" >> a.save => #
Article.all() returns all the articles in the database. >> Article.all => [#
] DBZ Models are plain objects you can define methods and redefine built-ins. >> Article.class_eval {def inspect() "" end } => nil >> Article.all => [] DBZ provides a rich database lookup API. >> Article.find(:id=>1) => not implemented python stuff >>> Article.objects.get(headline__startswith='Area woman') >>> Article.objects.get(pub_date__year=2005) >>> Article.objects.get(pub_date__year=2005, pub_date__month=7) >>> Article.objects.get(pub_date__year=2005, pub_date__month=7, pub_date__day=28) >>> Article.objects.filter(pub_date__year=2005) [] >>> Article.objects.filter(pub_date__year=2004) [] >>> Article.objects.filter(pub_date__year=2005, pub_date__month=7) [] DBZ returns nil if parameters for finders don't match anything >> Article.find(:id=>2) => nil >> Article.find(:pub_date=>Time.now) => nil >> Article[123] => nil Lookup by a primary key is the most common case, so DBZ provides a shortcut for primary-key exact lookups. The following is identical to articles.get(id=1). >> Article.find(:id=>1) => >> Article[1] => pk can be used as a shortcut for the primary key name in any query >>> Article.objects.filter(pk__in=[1]) [] Model instances of the "same type" and same ID are considered equal. >> a = Article[1] => >> b = Article.find(:id=>1) => >> a == b => true XXX: look for better name :) You can initialize a model instance using positional arguments, which should match the field order as defined in the model. >> a2 = Article.new2(nil, 'Second article', Date.new(2005, 7, 29)) => >> a2.save => >> a2.id => 2 >> a2.headline => "Second article" >> a2.pub_date => # Or, you can use keyword arguments. >> a3 = Article.new(:id=>nil, :headline=>'Third article', :pub_date=>Date.new(2005, 7, 30)) => >> a3.save => >> a3.id => 3 >> a3.headline => "Third article" >> a3.pub_date => # You _cannot_ mix and match position and keyword arguments. This is evil, but if you want you can esasily define your own initializers. Do not use invalid keyword arguments. If you do that DBZ will notice it and complain so that you can catch errors as soon as possible. >> Article.new(:id=>nil, :headline=>'Invalid', :pub_date=>Date.new(2005, 7, 31), :foo=>'bar') rescue $! => #> a4 = Article.new(:headline=>'Article 4', :pub_date=>Date.new(2005, 7, 31)) => >> a4.save => >> a4.id => 4 >> a4.headline => "Article 4" If you leave off a field with "default" set, Django will use the default but it will be set on save. >> a5 = Article.new(:pub_date=>Date.new(2005, 7, 31)) => >> a5.headline => nil >> a5.save => >> a5.headline => "Default headline" For DateTimeFields, Django saves as much precision (in seconds) as you give it. >>> a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 31, 12, 30)) >>> a7.save() >>> Article.objects.get(id__exact=7).pub_date datetime.datetime(2005, 7, 31, 12, 30) >>> a8 = Article(headline='Article 8', pub_date=datetime(2005, 7, 31, 12, 30, 45)) >>> a8.save() >>> Article.objects.get(id__exact=8).pub_date datetime.datetime(2005, 7, 31, 12, 30, 45) >>> a8.id 8L Saving an object again doesn't create a new object -- it just saves the old one. >>> a8.save() >>> a8.id 8L >>> a8.headline = 'Updated article 8' >>> a8.save() >>> a8.id 8L >>> a7 == a8 False >>> a8 == Article.objects.get(id__exact=8) True >>> a7 != a8 True >>> Article.objects.get(id__exact=8) != Article.objects.get(id__exact=7) True >>> Article.objects.get(id__exact=8) == Article.objects.get(id__exact=7) False dates() returns a list of available dates of the given scope for the given field. >>> Article.objects.dates('pub_date', 'year') [datetime.datetime(2005, 1, 1, 0, 0)] >>> Article.objects.dates('pub_date', 'month') [datetime.datetime(2005, 7, 1, 0, 0)] >>> Article.objects.dates('pub_date', 'day') [datetime.datetime(2005, 7, 28, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 31, 0, 0)] >>> Article.objects.dates('pub_date', 'day', order='ASC') [datetime.datetime(2005, 7, 28, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 31, 0, 0)] >>> Article.objects.dates('pub_date', 'day', order='DESC') [datetime.datetime(2005, 7, 31, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 28, 0, 0)] dates() requires valid arguments. >>> Article.objects.dates() Traceback (most recent call last): ... TypeError: dates() takes at least 3 arguments (1 given) >>> Article.objects.dates('invalid_field', 'year') Traceback (most recent call last): ... FieldDoesNotExist: Article has no field named 'invalid_field' >>> Article.objects.dates('pub_date', 'bad_kind') Traceback (most recent call last): ... AssertionError: 'kind' must be one of 'year', 'month' or 'day'. >>> Article.objects.dates('pub_date', 'year', order='bad order') Traceback (most recent call last): ... AssertionError: 'order' must be either 'ASC' or 'DESC'. Use iterator() with dates() to return a generator that lazily requests each result one at a time, to save memory. >>> for a in Article.objects.dates('pub_date', 'day', order='DESC').iterator(): ... print repr(a) datetime.datetime(2005, 7, 31, 0, 0) datetime.datetime(2005, 7, 30, 0, 0) datetime.datetime(2005, 7, 29, 0, 0) datetime.datetime(2005, 7, 28, 0, 0) You can combine queries with & and |. >>> s1 = Article.objects.filter(id__exact=1) >>> s2 = Article.objects.filter(id__exact=2) >>> s1 | s2 [, ] >>> s1 & s2 [] You can get the number of objects like this: >>> len(Article.objects.filter(id__exact=1)) 1 You can get items using index and slice notation. >>> Article.objects.all()[0] >>> Article.objects.all()[1:3] [, ] >>> s3 = Article.objects.filter(id__exact=3) >>> (s1 | s2 | s3)[::2] [, ] Slices (without step) are lazy: >>> Article.objects.all()[0:5].filter() [, , , , ] Slicing again works: >>> Article.objects.all()[0:5][0:2] [, ] >>> Article.objects.all()[0:5][:2] [, ] >>> Article.objects.all()[0:5][4:] [] >>> Article.objects.all()[0:5][5:] [] Some more tests! >>> Article.objects.all()[2:][0:2] [, ] >>> Article.objects.all()[2:][:2] [, ] >>> Article.objects.all()[2:][2:3] [] Note that you can't use 'offset' without 'limit' (on some dbs), so this doesn't work: >>> Article.objects.all()[2:] Traceback (most recent call last): ... AssertionError: 'offset' is not allowed without 'limit' Also, once you have sliced you can't filter, re-order or combine >>> Article.objects.all()[0:5].filter(id=1) Traceback (most recent call last): ... AssertionError: Cannot filter a query once a slice has been taken. >>> Article.objects.all()[0:5].order_by('id') Traceback (most recent call last): ... AssertionError: Cannot reorder a query once a slice has been taken. >>> Article.objects.all()[0:1] & Article.objects.all()[4:5] Traceback (most recent call last): ... AssertionError: Cannot combine queries once a slice has been taken. Negative slices are not supported, due to database constraints. (hint: inverting your ordering might do what you need). >>> Article.objects.all()[-1] Traceback (most recent call last): ... AssertionError: Negative indexing is not supported. >>> Article.objects.all()[0:-5] Traceback (most recent call last): ... AssertionError: Negative indexing is not supported. An Article instance doesn't have access to the "objects" attribute. That's only available on the class. >>> a7.objects.all() Traceback (most recent call last): ... AttributeError: Manager isn't accessible via Article instances >>> a7.objects Traceback (most recent call last): ... AttributeError: Manager isn't accessible via Article instances Bulk delete test: How many objects before and after the delete? >>> Article.objects.all() [, , , , , , , ] >>> Article.objects.filter(id__lte=4).delete() >>> Article.objects.all() [, , , ] """} from django.conf import settings building_docs = getattr(settings, 'BUILDING_DOCS', False) if building_docs or settings.DATABASE_ENGINE == 'postgresql': __test__['API_TESTS'] += """ In PostgreSQL, microsecond-level precision is available. >>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180)) >>> a9.save() >>> Article.objects.get(id__exact=9).pub_date datetime.datetime(2005, 7, 31, 12, 30, 45, 180) """ if building_docs or settings.DATABASE_ENGINE == 'mysql': __test__['API_TESTS'] += """ In MySQL, microsecond-level precision isn't available. You'll lose microsecond-level precision once the data is saved. >>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180)) >>> a9.save() >>> Article.objects.get(id__exact=9).pub_date datetime.datetime(2005, 7, 31, 12, 30, 45) """ __test__['API_TESTS'] += """ You can manually specify the primary key when creating a new object. >>> a101 = Article(id=101, headline='Article 101', pub_date=datetime(2005, 7, 31, 12, 30, 45)) >>> a101.save() >>> a101 = Article.objects.get(pk=101) >>> a101.headline 'Article 101' You can create saved objects in a single step >>> a10 = Article.objects.create(headline="Article 10", pub_date=datetime(2005, 7, 31, 12, 30, 45)) >>> Article.objects.get(headline="Article 10") Edge-case test: A year lookup should retrieve all objects in the given year, including Jan. 1 and Dec. 31. >>> a11 = Article.objects.create(headline='Article 11', pub_date=datetime(2008, 1, 1)) >>> a12 = Article.objects.create(headline='Article 12', pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999)) >>> Article.objects.filter(pub_date__year=2008) [, ] """