Changeset 7871
- Timestamp:
- 07/08/08 16:53:38 (2 months ago)
- Files:
-
- django/trunk/django/db/models/base.py (modified) (19 diffs)
- django/trunk/django/db/models/query.py (modified) (32 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/db/models/base.py
r7859 r7871 4 4 import os 5 5 from itertools import izip 6 try: 7 set 8 except NameError: 9 from sets import Set as set # Python 2.3 fallback. 6 10 7 11 import django.db.models.manipulators # Imported to register signal handler. … … 24 28 from django.conf import settings 25 29 26 try:27 set28 except NameError:29 from sets import Set as set # Python 2.3 fallback30 30 31 31 class ModelBase(type): 32 "Metaclass for all models" 32 """ 33 Metaclass for all models. 34 """ 33 35 def __new__(cls, name, bases, attrs): 34 36 super_new = super(ModelBase, cls).__new__ … … 145 147 146 148 def _prepare(cls): 147 # Creates some methods once self._meta has been populated. 149 """ 150 Creates some methods once self._meta has been populated. 151 """ 148 152 opts = cls._meta 149 153 opts._prepare(cls) … … 163 167 164 168 dispatcher.send(signal=signals.class_prepared, sender=cls) 169 165 170 166 171 class Model(object): … … 268 273 def save(self): 269 274 """ 270 Save the current instance. Override this in a subclass if you want to275 Saves the current instance. Override this in a subclass if you want to 271 276 control the saving process. 272 277 """ … … 294 299 # If we are in a raw save, save the object exactly as presented. 295 300 # That means that we don't try to be smart about saving attributes 296 # that might have come from the parent class - we just save the 301 # that might have come from the parent class - we just save the 297 302 # attributes we have been given to the class we have been given. 298 303 if not raw: … … 302 307 303 308 non_pks = [f for f in meta.local_fields if not f.primary_key] 304 309 305 310 # First, try an UPDATE. If that doesn't update anything, do an INSERT. 306 311 pk_val = self._get_pk_val(meta) … … 372 377 def _collect_sub_objects(self, seen_objs, parent=None, nullable=False): 373 378 """ 374 Recursively populates seen_objs with all objects related to this object. 379 Recursively populates seen_objs with all objects related to this 380 object. 381 375 382 When done, seen_objs.items() will be in the format: 376 383 [(model_class, {pk_val: obj, pk_val: obj, ...}), 377 (model_class, {pk_val: obj, pk_val: obj, ...}), ...]384 (model_class, {pk_val: obj, pk_val: obj, ...}), ...] 378 385 """ 379 386 pk_val = self._get_pk_val() … … 412 419 assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) 413 420 414 # Find all the objects than need to be deleted 421 # Find all the objects than need to be deleted. 415 422 seen_objs = CollectedObjects() 416 423 self._collect_sub_objects(seen_objs) 417 424 418 # Actually delete the objects 425 # Actually delete the objects. 419 426 delete_objects(seen_objs) 420 427 … … 455 462 456 463 def _get_FIELD_filename(self, field): 457 if getattr(self, field.attname): # value is not blank464 if getattr(self, field.attname): # Value is not blank. 458 465 return os.path.normpath(os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))) 459 466 return '' 460 467 461 468 def _get_FIELD_url(self, field): 462 if getattr(self, field.attname): # value is not blank469 if getattr(self, field.attname): # Value is not blank. 463 470 import urlparse 464 471 return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/') … … 475 482 pass 476 483 477 #478 484 # Check for old-style usage (files-as-dictionaries). Warn here first 479 485 # since there are multiple locations where we need to support both new 480 486 # and old usage. 481 #482 487 if isinstance(raw_field, dict): 483 488 import warnings 484 489 warnings.warn( 485 490 message = "Representing uploaded files as dictionaries is"\ 486 " deprec ted. Use django.core.files.SimpleUploadedFile"\491 " deprecated. Use django.core.files.SimpleUploadedFile"\ 487 492 " instead.", 488 493 category = DeprecationWarning, … … 509 514 filename = field.get_filename(filename) 510 515 511 # 512 # If the filename already exists, keep adding an underscore to the name of 513 # the file until the filename doesn't exist. 514 # 516 # If the filename already exists, keep adding an underscore to the name 517 # of the file until the filename doesn't exist. 515 518 while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)): 516 519 try: 517 520 dot_index = filename.rindex('.') 518 except ValueError: # filename has no dot 521 except ValueError: # filename has no dot. 519 522 filename += '_' 520 523 else: 521 524 filename = filename[:dot_index] + '_' + filename[dot_index:] 522 # 523 # Save the file name on the object and write the file to disk 524 # 525 525 526 # Save the file name on the object and write the file to disk. 526 527 setattr(self, field.attname, filename) 527 528 528 full_filename = self._get_FIELD_filename(field) 529 530 529 if hasattr(raw_field, 'temporary_file_path'): 531 530 # This file has a file path that we can move. 532 531 raw_field.close() 533 532 file_move_safe(raw_field.temporary_file_path(), full_filename) 534 535 533 else: 536 534 # This is a normal uploadedfile that we can stream. … … 543 541 544 542 # Save the width and/or height, if applicable. 545 if isinstance(field, ImageField) and (field.width_field or field.height_field): 543 if isinstance(field, ImageField) and \ 544 (field.width_field or field.height_field): 546 545 from django.utils.images import get_image_dimensions 547 546 width, height = get_image_dimensions(full_filename) … … 551 550 setattr(self, field.height_field, height) 552 551 553 # Save the object because it has changed unless save is False552 # Save the object because it has changed, unless save is False. 554 553 if save: 555 554 self.save() … … 570 569 setattr(self, cachename, get_image_dimensions(filename)) 571 570 return getattr(self, cachename) 571 572 572 573 573 ############################################ … … 586 586 transaction.commit_unless_managed() 587 587 588 588 589 def method_get_order(ordered_obj, self): 589 590 rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name) … … 593 594 ordered_obj.objects.filter(**{order_name: rel_val}).values(pk_name)] 594 595 596 595 597 ############################################## 596 598 # HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) # … … 599 601 def get_absolute_url(opts, func, self, *args, **kwargs): 600 602 return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self, *args, **kwargs) 603 601 604 602 605 ######## … … 611 614 def subclass_exception(name, parent, unused): 612 615 return types.ClassType(name, (parent,), {}) 613 614 616 else: 615 617 def subclass_exception(name, parent, module): 616 618 return type(name, (parent,), {'__module__': module}) 617 django/trunk/django/db/models/query.py
r7782 r7871 14 14 ITER_CHUNK_SIZE = CHUNK_SIZE 15 15 16 # Pull into this namespace for backwards compatibility 16 # Pull into this namespace for backwards compatibility. 17 17 EmptyResultSet = sql.EmptyResultSet 18 18 … … 20 20 pass 21 21 22 22 23 class CollectedObjects(object): 23 24 """ 24 A container that stores keys and lists of values along with 25 remembering theparent objects for all the keys.26 27 This is used for the database object deletion routines so that we 28 ca n calculate the 'leaf' objects which should be deleted first.25 A container that stores keys and lists of values along with remembering the 26 parent objects for all the keys. 27 28 This is used for the database object deletion routines so that we can 29 calculate the 'leaf' objects which should be deleted first. 29 30 """ 30 31 … … 35 36 def add(self, model, pk, obj, parent_model, nullable=False): 36 37 """ 37 Adds an item. 38 model is the class of the object being added, 39 pk is the primary key, obj is the object itself, 40 parent_model is the model of the parent object 41 that this object was reached through, nullable should 42 be True if this relation is nullable. 43 44 If the item already existed in the structure, 45 returns true, otherwise false. 38 Adds an item to the container. 39 40 Arguments: 41 * model - the class of the object being added. 42 * pk - the primary key. 43 * obj - the object itself. 44 * parent_model - the model of the parent object that this object was 45 reached through. 46 * nullable - should be True if this relation is nullable. 47 48 Returns True if the item already existed in the structure and 49 False otherwise. 46 50 """ 47 51 d = self.data.setdefault(model, SortedDict()) 48 52 retval = pk in d 49 53 d[pk] = obj 50 # Nullable relationships can be ignored -- they 51 # are nulled out before deleting, and therefore 52 # do not affect the order in which objects have 53 # to be deleted. 54 # Nullable relationships can be ignored -- they are nulled out before 55 # deleting, and therefore do not affect the order in which objects 56 # have to be deleted. 54 57 if parent_model is not None and not nullable: 55 58 self.children.setdefault(parent_model, []).append(model) 56 57 59 return retval 58 60 … … 78 80 def ordered_keys(self): 79 81 """ 80 Returns the models in the order that they should be 81 dealth with i.e. models with no dependencies first.82 Returns the models in the order that they should be dealt with (i.e. 83 models with no dependencies first). 82 84 """ 83 85 dealt_with = SortedDict() … … 92 94 found = True 93 95 if not found: 94 raise CyclicDependency("There is a cyclic dependency of items to be processed.") 96 raise CyclicDependency( 97 "There is a cyclic dependency of items to be processed.") 95 98 96 99 return dealt_with.keys() … … 98 101 def unordered_keys(self): 99 102 """ 100 Fallback for the case where is a cyclic dependency but we 101 don't care. 103 Fallback for the case where is a cyclic dependency but we don't care. 102 104 """ 103 105 return self.data.keys() 104 106 107 105 108 class QuerySet(object): 106 "Represents a lazy database lookup for a set of objects" 109 """ 110 Represents a lazy database lookup for a set of objects. 111 """ 107 112 def __init__(self, model=None, query=None): 108 113 self.model = model … … 117 122 def __getstate__(self): 118 123 """ 119 Allows the Query set to be pickled.124 Allows the QuerySet to be pickled. 120 125 """ 121 126 # Force the cache to be fully populated. … … 132 137 # Since __len__ is called quite frequently (for example, as part of 133 138 # list(qs), we make some effort here to be as efficient as possible 134 # whilst not messing up any existing iterators against the queryset.139 # whilst not messing up any existing iterators against the QuerySet. 135 140 if self._result_cache is None: 136 141 if self._iter: … … 174 179 175 180 def __getitem__(self, k): 176 "Retrieve an item or slice from the set of results." 181 """ 182 Retrieves an item or slice from the set of results. 183 """ 177 184 if not isinstance(k, (slice, int, long)): 178 185 raise TypeError … … 265 272 integer. 266 273 267 If the queryset is already cached (i.e. self._result_cache is set) this274 If the QuerySet is already cached (i.e. self._result_cache is set) this 268 275 simply returns the length of the cached results set to avoid multiple 269 276 SELECT COUNT(*) calls. … … 291 298 def create(self, **kwargs): 292 299 """ 293 Create a new object with the given kwargs, saving it to the database300 Creates a new object with the given kwargs, saving it to the database 294 301 and returning the created object. 295 302 """ … … 426 433 def dates(self, field_name, kind, order='ASC'): 427 434 """ 428 Returns a list of datetime objects representing all available dates 429 forthe given field_name, scoped to 'kind'.435 Returns a list of datetime objects representing all available dates for 436 the given field_name, scoped to 'kind'. 430 437 """ 431 438 assert kind in ("month", "year", "day"), \ … … 442 449 def none(self): 443 450 """ 444 Returns an empty queryset.451 Returns an empty QuerySet. 445 452 """ 446 453 return self._clone(klass=EmptyQuerySet) … … 486 493 """ 487 494 Returns a new QuerySet instance with filter_obj added to the filters. 495 488 496 filter_obj can be a Q object (or anything with an add_to_query() 489 497 method) or a dictionary of keyword lookup arguments. … … 501 509 def select_related(self, *fields, **kwargs): 502 510 """ 503 Returns a new QuerySet instance that will select related objects. If 504 fields are specified, they must be ForeignKey fields and only those 511 Returns a new QuerySet instance that will select related objects. 512 513 If fields are specified, they must be ForeignKey fields and only those 505 514 related objects are included in the selection. 506 515 """ … … 522 531 def dup_select_related(self, other): 523 532 """ 524 Copies the related selection status from the queryset 'other' to the525 current queryset.533 Copies the related selection status from the QuerySet 'other' to the 534 current QuerySet. 526 535 """ 527 536 self.query.select_related = other.query.select_related 528 537 529 538 def order_by(self, *field_names): 530 """Returns a new QuerySet instance with the ordering changed.""" 539 """ 540 Returns a new QuerySet instance with the ordering changed. 541 """ 531 542 assert self.query.can_filter(), \ 532 543 "Cannot reorder a query once a slice has been taken." … … 545 556 546 557 def extra(self, select=None, where=None, params=None, tables=None, 547 order_by=None, select_params=None):548 """ 549 Add extra SQL fragments to the query.558 order_by=None, select_params=None): 559 """ 560 Adds extra SQL fragments to the query. 550 561 """ 551 562 assert self.query.can_filter(), \ … … 557 568 def reverse(self): 558 569 """ 559 Reverses the ordering of the queryset.570 Reverses the ordering of the QuerySet. 560 571 """ 561 572 clone = self._clone() … … 590 601 def _merge_sanity_check(self, other): 591 602 """ 592 Checks that we are merging two comparable queryset classes. By default603 Checks that we are merging two comparable QuerySet classes. By default 593 604 this does nothing, but see the ValuesQuerySet for an example of where 594 605 it's useful. 595 606 """ 596 607 pass 608 597 609 598 610 class ValuesQuerySet(QuerySet): … … 618 630 retrieving. 619 631 620 Called by the _clone() method after initiali sing the rest of the632 Called by the _clone() method after initializing the rest of the 621 633 instance. 622 634 """ … … 658 670 raise TypeError("Merging '%s' classes must involve the same values in each case." 659 671 % self.__class__.__name__) 672 660 673 661 674 class ValuesListQuerySet(ValuesQuerySet): … … 682 695 return clone 683 696 697 684 698 class DateQuerySet(QuerySet): 685 699 def iterator(self): … … 690 704 Sets up any special features of the query attribute. 691 705 692 Called by the _clone() method after initiali sing the rest of the706 Called by the _clone() method after initializing the rest of the 693 707 instance. 694 708 """ … … 707 721 return c 708 722 723 709 724 class EmptyQuerySet(QuerySet): 710 725 def __init__(self, model=None, query=None): … … 733 748 # (it raises StopIteration immediately). 734 749 yield iter([]).next() 750 735 751 736 752 # QOperator, QNot, QAnd and QOr are temporarily retained for backwards … … 744 760 QOr = QAnd = QOperator 745 761 762 746 763 def QNot(q): 747 764 warnings.warn('Use ~q instead of QNot(q)', DeprecationWarning, stacklevel=2) 748 765 return ~q 749 766 767 750 768 def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0, 751 requested=None):769 requested=None): 752 770 """ 753 771 Helper function that recursively returns an object with the specified … … 775 793 return obj, index_end 776 794 795 777 796 def delete_objects(seen_objs): 778 797 """ … … 783 802 ordered_classes = seen_objs.keys() 784 803 except CyclicDependency: 785 # if there is a cyclic dependency, we cannot in general delete786 # the objects. However, if an appropriate transaction is set787 # up, or if the database is lax enough, it will succeed.788 # So for now, we go ahead and try anway.804 # If there is a cyclic dependency, we cannot in general delete the 805 # objects. However, if an appropriate transaction is set up, or if the 806 # database is lax enough, it will succeed. So for now, we go ahead and 807 # try anyway. 789 808 ordered_classes = seen_objs.unordered_keys() 790 809 … … 795 814 obj_pairs[cls] = items 796 815 797 # Pre notify all instances to be deleted816 # Pre-notify all instances to be deleted. 798 817 for pk_val, instance in items: 799 818 dispatcher.send(signal=signals.pre_delete, sender=cls, … … 809 828 update_query.clear_related(field, pk_list) 810 829 811 # Now delete the actual data 830 # Now delete the actual data. 812 831 for cls in ordered_classes: 813 832 items = obj_pairs[cls] … … 832 851 transaction.commit_unless_managed() 833 852 853 834 854 def insert_query(model, values, return_id=False, raw_values=False): 835 855 """ … … 841 861 query.insert_values(values, raw_values) 842 862 return query.execute_sql(return_id) 843
