166 | | See NamespaceSimplification for details. |
| 166 | {{{django.utils.httpwrappers}}} has moved to {{{django.http}}}. |
| 167 | |
| 168 | {{{django.core.exceptions.Http404}}} has moved to {{{django.http.Http404}}}. |
| 169 | |
| 170 | {{{django.core.template}}} has moved to {{{django.template}}}. |
| 171 | |
| 172 | {{{django.core.formfields}}} has moved to {{{django.forms}}}. |
| 173 | |
| 174 | {{{django.core.extensions}}} has moved to {{{django.shortcuts}}}. |
| 175 | |
| 176 | {{{django.core.extensions.DjangoContext}}} has been renamed to {{{RequestContext}}} and moved to {{{django.template.RequestContext}}}. |
| 177 | |
| 178 | You'll need to update {{{TEMPLATE_LOADERS}}} in your settings from: |
| 179 | {{{ |
| 180 | #!python |
| 181 | TEMPLATE_LOADERS = ( |
| 182 | 'django.core.template.loaders.filesystem.load_template_source', |
| 183 | 'django.core.template.loaders.app_directories.load_template_source', |
| 184 | # 'django.core.template.loaders.eggs.load_template_source', |
| 185 | ) |
| 186 | }}} |
| 187 | |
| 188 | ...to: |
| 189 | |
| 190 | {{{ |
| 191 | #!python |
| 192 | TEMPLATE_LOADERS = ( |
| 193 | 'django.template.loaders.filesystem.load_template_source', |
| 194 | 'django.template.loaders.app_directories.load_template_source', |
| 195 | # 'django.template.loaders.eggs.load_template_source', |
| 196 | ) |
| 197 | }}} |
| 198 | |
| 199 | The "auth" and "core" models have been split and moved to {{{django.contrib}}} as follows: |
| 200 | |
| 201 | * {{{django.models.auth}}} has moved to {{{django.contrib.auth.models}}}. |
| 202 | * {{{django.models.core.sites}}} has moved to {{{django.contrib.sites.models}}}. |
| 203 | * {{{django.models.core.contenttypes}}} has moved to {{{django.contrib.contenttypes.models}}}. |
| 204 | * {{{django.models.core.packages}}} has moved to {{{django.contrib.contenttypes.models}}}. (Note that "packages" are going away before magic-removal is done.) |
| 205 | |
| 206 | Session middleware has moved from {{{django.middleware.sessions.SessionMiddleware}}} to {{{django.contrib.sessions.middleware.SessionMiddleware}}}. Make sure to update your {{{MIDDLEWARE_CLASSES}}} setting, if you're using sessions. |
| 207 | |
| 208 | Also, the {{{Session}}} model has moved from django/models/core.py to django/contrib/sessions/models.py. If you're accessing the {{{Session}}} model for some reason, note that location change. |
236 | | {{{ |
237 | | #!python |
238 | | from myproject.people.models import Person |
239 | | p_list = Person.objects.get_list() |
240 | | p = Person.objects.get_object() |
241 | | }}} |
242 | | |
243 | | This doesn't work from an instance. |
244 | | |
245 | | {{{ |
246 | | #!python |
247 | | p = Person.objects.get_object(pk=1) |
248 | | p.objects.get_list() # Raises AttributeError |
| 314 | A model class's {{{objects}}} attribute is an instance of {{{django.db.models.manager.Manager}}}. A manager has the following methods, all of which return a {{{QuerySet}}} instance. |
| 315 | |
| 316 | * {{{all()}}} -- Returns a {{{QuerySet}}} of all objects in the database. This is like the old {{{get_list()}}}. Takes no arguments. |
| 317 | * {{{filter(**kwargs)}}} -- Returns a {{{QuerySet}}}, filtered by the given keyword arguments. Lookup arguments are in the same style as previously, e.g. {{{pubdate__year=2005}}}, except you can leave off {{{__exact}}} as a convenience. For example, {{{name='John'}}} and {{{name__exact='John'}}} are equivalent. |
| 318 | * {{{order_by(*fieldnames)}}} -- Returns a {{{QuerySet}}} |
| 319 | * {{{count()}}} -- Returns the count of all objects in the database. |
| 320 | * {{{dates(field_name, kind)}}} -- Like the old {{{get_FIELD_list()}}} for date fields. For example, old-school {{{get_pubdate_list('year')}}} is now {{{dates('pubdate', 'year')}}}. |
| 321 | * {{{delete()}}} -- Deletes all objects. |
| 322 | * {{{distinct()}}} -- Returns a {{{QuerySet}}} with DISTINCT set. |
| 323 | * {{{extra(select=None, where=None, params=None, tables=None)}}} -- Sets the {{{select}}}, {{{where}}}, {{{params}}} and {{{tables}}} arguments, which are in the same format as before. |
| 324 | * {{{get(**kwargs)}}} -- Like the old {{{get_object()}}}. Returns an object or raises {{{DoesNotExist}}} on error. |
| 325 | * {{{in_bulk(id_list)}}} -- Like the old {{{get_in_bulk()}}}. |
| 326 | * {{{iterator()}}} -- Returns a generator that iterators over results. |
| 327 | * {{{select_related()}}} -- Returns a {{{QuerySet}}} with the "select related" option (which acts the same as before) set. |
| 328 | * {{{values(*fieldnames)}}} -- Like the old {{{get_values()}}}. |
| 329 | |
| 330 | Each {{{QuerySet}}} has the following methods, which return a clone of the query set with the appropriate changes made: |
| 331 | |
| 332 | * {{{filter(**kwargs)}}} |
| 333 | * {{{order_by(*fieldnames)}}} |
| 334 | * {{{iterator()}}} |
| 335 | * {{{count()}}} |
| 336 | * {{{get(**kwargs)}}} |
| 337 | * {{{delete()}}} |
| 338 | * {{{filter(**kwargs)}}} |
| 339 | * {{{select_related()}}} |
| 340 | * {{{order_by(*fieldnames)}}} |
| 341 | * {{{distinct()}}} |
| 342 | * {{{extra(select=None, where=None, params=None, tables=None)}}} |
| 343 | |
| 344 | Here are some examples, which use the following models: |
| 345 | |
| 346 | {{{ |
| 347 | #!python |
| 348 | class Reporter(models.Model): |
| 349 | fname = models.CharField(maxlength=30) |
| 350 | lname = models.CharField(maxlength=30) |
| 351 | |
| 352 | class Site(models.Model): |
| 353 | name = models.CharField(maxlength=20) |
| 354 | |
| 355 | class Article(models.Model): |
| 356 | headline = models.CharField(maxlength=50) |
| 357 | reporter = models.ForeignKey(Reporter) |
| 358 | pub_date = models.DateField() |
| 359 | sites = models.ManyToManyField(Site) |
| 360 | }}} |
| 361 | |
| 362 | || '''Old syntax''' || '''New syntax''' || |
| 363 | || {{{reporters.get_list()}}} || {{{Reporter.objects.all()}}} || |
| 364 | || {{{reporters.get_list(fname__exact='John')}}} || {{{Reporter.objects.filter(fname='John')}}} || |
| 365 | || {{{reporters.get_list(order_by=('-lname', 'fname'))}}} || {{{Reporter.objects.order_by('-lname', 'fname')}}} || |
| 366 | || {{{reporters.get_list(fname__exact='John', order_by=('lname',))}}} || {{{Reporter.objects.filter(fname='John').order_by('lname')}}} || |
| 367 | || {{{reporters.get_object(pk=3)}}} || {{{Reporter.objects.get(pk=3)}}} || |
| 368 | || {{{reporters.get_object(fname__contains='John')}}} || {{{Reporter.objects.get(fname__contains='John')}}} || |
| 369 | || {{{reporters.get_list(distinct=True)}}} || {{{Reporter.objects.distinct()}}} || |
| 370 | || {{{reporters.get_values()}}} || {{{Reporter.objects.values()}}} || |
| 371 | || {{{reporters.get_in_bulk([1, 2])}}} || {{{Reporter.objects.in_bulk([1, 2])}}} || |
| 372 | || {{{reporters.get_in_bulk([1, 2], fname__exact='John')}}} || {{{Reporter.objects.filter(fname='John').in_bulk([1, 2])}}} || |
| 373 | || '''Date lookup''' || || |
| 374 | || {{{articles.get_pub_date_list('year')}}} || {{{Article.objects.dates('pub_date', 'year')}}} || |
| 375 | || '''Many-to-one related lookup''' || || |
| 376 | || {{{article_obj.reporter_id}}} || {{{article_obj.reporter.id}}} || |
| 377 | || {{{article_obj.get_reporter()}}} || {{{article_obj.reporter}}} || |
| 378 | || {{{reporter_obj.get_article_list()}}} || {{{reporter_obj.article_set.all()}}} || |
| 379 | || {{{reporter_obj.get_article_list(headline__exact='Hello')}}} || {{{reporter_obj.article_set.filter(headline='Hello')}}} || |
| 380 | || {{{reporter_obj.get_article_count()}}} || {{{reporter_obj.article_set.count()}}} || |
| 381 | || {{{reporter_obj.add_article(headline='Foo')}}} || {{{reporter_obj.article_set.add(headline='Foo')}}} || |
| 382 | || (Alternate syntax) || {{{reporter_obj.article_set.add(article_obj)}}} || |
| 383 | || ("values" lookup, etc., not previously possible) || {{{reporter_obj.article_set.values()}}} || |
| 384 | || '''Many-to-many related lookup''' || || |
| 385 | || {{{article_obj.get_site_list()}}} || {{{article_obj.sites.all()}}} || |
| 386 | || {{{article_obj.set_sites([s1.id, s2.id])}}} || {{{article_obj.sites.clear(); article_obj.sites.add(s1); article_obj.sites.add(s2)}}} || |
| 387 | || {{{article_obj.set_sites([s1.id]) # deletion}}} || {{{article_obj.sites.remove(s2)}}} || |
| 388 | || {{{site_obj.get_reporter_list()}}} || {{{site_obj.reporter_set.all()}}} || |
| 389 | |
| 390 | Note that related-object lookup uses the default manager of the related object, which means the API for accessing related objects is completely consistent with the API for accessing objects via a manager. |
| 391 | |
| 392 | Also note that managers can't be accessed from instances: |
| 393 | |
| 394 | {{{ |
| 395 | #!python |
| 396 | p = Person.objects.get(pk=1) |
| 397 | p.objects.all() # Raises AttributeError |
397 | | === Moved "auth" and "core" models to django.contrib === |
398 | | |
399 | | See http://groups.google.com/group/django-developers/browse_thread/thread/276d071a74543448/7d4b1c40c2d53393 |
400 | | |
401 | | * Old: {{{django.models.auth}}} |
402 | | * New: {{{django.contrib.auth.models}}} |
403 | | |
404 | | * Old: {{{django.models.core.sites}}} |
405 | | * New: {{{django.contrib.sites.models}}} |
406 | | |
407 | | * Old: {{{django.models.core.contenttypes}}} |
408 | | * New: {{{django.contrib.contenttypes.models}}} |
409 | | |
410 | | * Old: {{{django.models.core.packages}}} |
411 | | * New: {{{django.contrib.contenttypes.models}}} ("Packages" will most likely be removed in the future.) |
412 | | |
413 | | === Moved Session model and middleware from core to django.contrib === |
414 | | |
415 | | The location of the session middleware has changed. |
416 | | |
417 | | * Old: {{{django.middleware.sessions.SessionMiddleware}}} |
418 | | * New: {{{django.contrib.sessions.middleware.SessionMiddleware}}} |
419 | | |
420 | | Make sure to update your {{{MIDDLEWARE_CLASSES}}} setting, if you're using sessions. |
421 | | |
422 | | Also, the {{{Session}}} model has moved from django/models/core.py to django/contrib/sessions/models.py. If you're accessing the {{{Session}}} model for some reason, note that location change. |
497 | | === You can override table-level functions === |
498 | | |
499 | | You can override any table-level functions, such as {{{get_list()}}} or {{{get_object()}}}. Do this by creating a custom {{{models.Manager}}} subclass and passing it to your model. |
500 | | |
501 | | {{{ |
502 | | #!python |
503 | | from django.db import models |
504 | | class PersonManager(models.Manager): |
505 | | def get_list(self, **kwargs): |
506 | | # Changes get_list() to hard-code a limit=10. |
507 | | kwargs['limit'] = 10 |
508 | | return models.Manager.get_list(self, **kwargs) # Call the "real" get_list() method. |
509 | | |
510 | | class Person(models.Model): |
511 | | first_name = models.CharField(maxlength=30) |
512 | | last_name = models.CharField(maxlength=30) |
513 | | objects = PersonManager() |
514 | | }}} |
515 | | |
516 | | If a manager needs to access its associated class, it should use {{{self.model}}}. Example: |
517 | | |
518 | | {{{ |
519 | | #!python |
520 | | class PersonManager(models.Manager): |
521 | | def get_fun_person(self): |
522 | | try: |
523 | | return self.get_object(fun__exact=True) |
524 | | except self.model.DoesNotExist: |
525 | | print "Doesn't exist." |
526 | | }}} |
527 | | |
528 | | |
529 | | |
530 | | |
531 | | |
| 590 | === You can override default QuerySets === |
| 591 | |
| 592 | You can specify the default QuerySet (see "Descriptor fields" above) that a manager uses. For example: |
| 593 | |
| 594 | {{{ |
| 595 | #!python |
| 596 | class PublishedBookManager(models.Manager): |
| 597 | def get_query_set(self): |
| 598 | return super(PublishedBookManager, self).get_query_set().filter(is_published=True) |
| 599 | |
| 600 | class Book(models.Model): |
| 601 | title = models.CharField(maxlength=50) |
| 602 | author = models.CharField(maxlength=30) |
| 603 | is_published = models.BooleanField() |
| 604 | published_objects = PublishedBookManager() |
| 605 | }}} |