Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

abstract_models.py 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. """
  2. Core address objects
  3. """
  4. import zlib
  5. from django.db import models
  6. from django.utils.translation import ugettext_lazy as _
  7. class AbstractAddress(models.Model):
  8. u"""
  9. Superclass address object
  10. This is subclassed and extended to provide models for
  11. user, shipping and billing addresses.
  12. The only required fields are last_name, line1 and postcode.
  13. """
  14. # @todo: Need a way of making these choice lists configurable
  15. # per project
  16. MR, MISS, MRS, MS, DR = ('Dr', 'Miss', 'Mrs', 'Ms', 'Dr')
  17. TITLE_CHOICES = (
  18. (MR, _("Mr")),
  19. (MISS, _("Miss")),
  20. (MRS, _("Mrs")),
  21. (MS, _("Ms")),
  22. (DR, _("Dr")),
  23. )
  24. title = models.CharField(_("Title"), max_length=64, choices=TITLE_CHOICES, blank=True)
  25. first_name = models.CharField(_("First name"), max_length=255, blank=True)
  26. last_name = models.CharField(_("Last name"), max_length=255)
  27. line1 = models.CharField(_("First line of address"), max_length=255)
  28. line2 = models.CharField(_("Second line of address"), max_length=255, blank=True)
  29. line3 = models.CharField(_("City"), max_length=255, blank=True)
  30. line4 = models.CharField(_("State/County"), max_length=255, blank=True)
  31. postcode = models.CharField(_("Post/Zip-code"), max_length=64)
  32. country = models.ForeignKey('address.Country')
  33. class Meta:
  34. abstract = True
  35. def save(self, *args, **kwargs):
  36. u"""Clean fields and save"""
  37. self._clean_fields()
  38. super(AbstractAddress, self).save(*args, **kwargs)
  39. def _clean_fields(self):
  40. u"""Clean up fields"""
  41. self.first_name = self.first_name.strip()
  42. for field in ['first_name', 'last_name', 'line1', 'line2', 'line3', 'line4', 'postcode']:
  43. self.__dict__[field] = self.__dict__[field].strip()
  44. # Ensure postcodes are always uppercase
  45. if self.postcode:
  46. self.postcode = self.postcode.upper()
  47. @property
  48. def summary(self):
  49. u"""
  50. Returns a single string summary of the address,
  51. separating fields using commas.
  52. """
  53. return u", ".join(self.active_address_fields())
  54. def populate_alternative_model(self, address_model):
  55. u"""
  56. For populating an address model using the matching fields
  57. from this one.
  58. This is used to convert a user address to a shipping address
  59. as part of the checkout process.
  60. """
  61. destination_field_names = list(address_model._meta.get_all_field_names())
  62. for field_name in self._meta.get_all_field_names():
  63. if field_name in destination_field_names and field_name != 'id':
  64. setattr(address_model, field_name, getattr(self, field_name))
  65. def active_address_fields(self):
  66. u"""
  67. Returns the non-empty components of the address, but merging the
  68. title, first_name and last_name into a single line.
  69. """
  70. self._clean_fields()
  71. return filter(lambda x: x, [self.salutation(), self.line1, self.line2, self.line3,
  72. self.line4, self.postcode, self.country.name])
  73. def salutation(self):
  74. u"""Returns the salutation"""
  75. return u" ".join([part for part in [self.title, self.first_name, self.last_name] if part])
  76. def __unicode__(self):
  77. return self.summary
  78. class AbstractCountry(models.Model):
  79. u"""International Organization for Standardization (ISO) 3166-1 Country list"""
  80. iso_3166_1_a2 = models.CharField(_('ISO 3166-1 alpha-2'), max_length=2, primary_key=True)
  81. iso_3166_1_a3 = models.CharField(_('ISO 3166-1 alpha-3'), max_length=3, null=True)
  82. iso_3166_1_numeric = models.PositiveSmallIntegerField(_('ISO 3166-1 numeric'), null=True)
  83. name = models.CharField(_('Official name (CAPS)'), max_length=128)
  84. printable_name = models.CharField(_('Country name'), max_length=128)
  85. is_highlighted = models.BooleanField(default=False)
  86. is_shipping_country = models.BooleanField(default=False)
  87. class Meta:
  88. abstract = True
  89. verbose_name = _('Country')
  90. verbose_name_plural = _('Countries')
  91. ordering = ('-is_highlighted', 'name',)
  92. def __unicode__(self):
  93. return self.printable_name
  94. class AbstractShippingAddress(AbstractAddress):
  95. u"""
  96. Shipping address.
  97. A shipping address should not be edited once the order has been placed -
  98. it should be read-only after that.
  99. """
  100. phone_number = models.CharField(max_length=32, blank=True, null=True)
  101. notes = models.TextField(blank=True, null=True, help_text="""Shipping notes""")
  102. class Meta:
  103. abstract = True
  104. verbose_name_plural = "shipping addresses"
  105. class AbstractUserAddress(AbstractShippingAddress):
  106. u"""
  107. A user address which forms an "AddressBook" for a user.
  108. We use a separate model to shipping and billing (even though there will be
  109. some data duplication) because we don't want shipping/billing addresses changed
  110. or deleted once an order has been placed. By having a separate model, we allow
  111. users the ability to add/edit/delete from their address book without affecting
  112. orders already placed.
  113. """
  114. user = models.ForeignKey('auth.User', related_name='addresses')
  115. # Customers can set which is their default billing address
  116. default_for_billing = models.BooleanField(default=False)
  117. # We keep track of the number of times an address has been used
  118. # as a shipping address so we can show the most popular ones
  119. # first at the checkout.
  120. num_orders = models.PositiveIntegerField(default=0)
  121. # A hash is kept to try and avoid duplicate addresses being added
  122. # to the address book.
  123. hash = models.CharField(max_length=255, db_index=True)
  124. date_created = models.DateTimeField(auto_now_add=True)
  125. def generate_hash(self):
  126. u"""Returns a hash of the address summary."""
  127. # We use an upper-case version of the summary
  128. return zlib.crc32(self.summary.strip().upper().encode('UTF8'))
  129. def save(self, *args, **kwargs):
  130. u"""Save a hash of the address fields"""
  131. # Save a hash of the address fields so we can check whether two
  132. # addresses are the same to avoid saving duplicates
  133. self.hash = self.generate_hash()
  134. super(AbstractUserAddress, self).save(*args, **kwargs)
  135. class Meta:
  136. abstract = True
  137. verbose_name_plural = "User addresses"
  138. ordering = ['-num_orders']
  139. class AbstractBillingAddress(AbstractAddress):
  140. u"""Billing address"""
  141. class Meta:
  142. abstract = True
  143. verbose_name_plural = "Billing addresses"