Advertisement
Guest User

Untitled

a guest
Oct 17th, 2019
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.97 KB | None | 0 0
  1. # ###### Address deduplication
  2. # Consider an Address model defined as follows:
  3. #
  4. # class UserAddress(models.Model):
  5. # user = models.ForeignKey(User)
  6. # name = models.CharField(max_length=255)
  7. # street_address = models.CharField(max_lenght=255)
  8. # street_address_line2 = models.CharField(max_lenght=255, blank=True, null=True)
  9. # zipcode = models.CharField(max_length=12, blank=True, null=True)
  10. # city = models.CharField(max_length=64)
  11. # state = models.CharField(max_length=64, blank=True, null=True)
  12. # country = models.CharField(max_length=2)
  13. # full_address = models.TextField(blank=True)
  14. #
  15. # def save(*args, **kwargs):
  16. # streetdata = f"{self.street_address}\n{self.street_address_line2}"
  17. # self.full_address = f"{streetdata}\n{self.zipcode} {self.city} {self.state} {self.country}"
  18. # super().save(*args, **kwargs)
  19. #
  20. # A UserAddress is saved every time the user changes something in the form, provided the form is valid.
  21. # The task is devising a way of removing partial addresses that are entirely a subset of the current address.
  22. # For example, assuming the following addresses are entered in the form(all belonging to the same user) in sequence:
  23. #
  24. # add1 = UserAddress(name="Max", city="Giventown")
  25. # add2 = UserAddress(name="Max Mustermann", street_address="Randomstreet", city="Giventown")
  26. # add3 = UserAddress(name="Max Mustermann", street_address="456 Randomstreet", city="Giventown")
  27. # add4 = UserAddress(name="Max Mustermann", street_address="789 Otherstreet", city="Giventown", country="NL")
  28. #
  29. # The expected result would be that only add3 and add4 are left in the DB at the end of the sequence
  30.  
  31.  
  32. """
  33. Approach:
  34.  
  35. Prior to save the user's UserAddress check if any address exists.
  36. If not, save it and return. Otherwise get the last address and compare with current address.
  37. If current address is superset of last address then update last address with current address.
  38. Otherwise save current address as new UserAddress.
  39.  
  40. """
  41.  
  42. class UserAddressManager(models.Manager):
  43. """ manager class to help find/get useraddress instances """
  44.  
  45. def address_count(self, user):
  46. return self.get_user_addresses(user).count()
  47.  
  48. def get_last_address(self, user):
  49. last_address = self.filter(user=user).last()
  50. if last_address:
  51. return last_address
  52. return None
  53.  
  54.  
  55. class UserAddress(models.Model):
  56. user = models.ForeignKey(User, on_delete=models.CASCADE)
  57. name = models.CharField(max_length=255)
  58. street_address = models.CharField(max_length=255)
  59. street_address_line2 = models.CharField(max_length=255, blank=True, null=True)
  60. zipcode = models.CharField(max_length=12, blank=True, null=True)
  61. city = models.CharField(max_length=64)
  62. state = models.CharField(max_length=64, blank=True, null=True)
  63. country = models.CharField(max_length=2)
  64. full_address = models.TextField(blank=True)
  65. objects = UserAddressManager()
  66.  
  67. @staticmethod
  68. def prepare_address_set(obj):
  69. """
  70. helper function to prepare comparable address format
  71. :param obj: instance of UserAddress
  72. :return: a set consists of units of a address
  73. """
  74. street_address_1 = obj.street_address.split() if obj.street_address else ['']
  75. street_address_2 = obj.street_address_line2.split() if obj.street_address_line2 else ['']
  76. extended_address = [obj.zipcode or '', obj.city or '', obj.state or '', obj.country or '']
  77. return set(street_address_1 + street_address_2 + extended_address)
  78.  
  79. def is_superset_of(self, address):
  80. """
  81. check if current address is superset of user's old address.
  82. :param address: instance of UserAddress
  83. :return: boolean
  84. """
  85. if not address:
  86. return False
  87. _last_address = self.prepare_address_set(address)
  88. _current_address = self.prepare_address_set(self)
  89.  
  90. return _current_address.issuperset(_last_address)
  91.  
  92. def add_or_update(self):
  93. last_address = UserAddress.objects.get_last_address(user=self.user)
  94. if last_address is None:
  95. self.save('allow_save')
  96. else:
  97. if self.is_superset_of(last_address):
  98. updated_address = {
  99. 'street_address': self.street_address,
  100. 'street_address_line2': self.street_address_line2,
  101. 'zipcode': self.zipcode,
  102. 'city': self.city,
  103. 'state': self.state,
  104. 'country': self.country
  105. }
  106. UserAddress.objects.filter(id=last_address.id).update(**updated_address)
  107. else:
  108. self.save('allow_save')
  109.  
  110. def save(self, *args, **kwargs):
  111. if 'allow_save' not in args:
  112. raise Exception('Using .save() method may cause redundancy.\n Use add_or_update method instead.')
  113.  
  114. streetdata = f"{self.street_address}\n{self.street_address_line2}"
  115. self.full_address = f"{streetdata}\n{self.zipcode} {self.city} {self.state} {self.country}"
  116. super().save(*args, **kwargs)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement