Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # ###### Address deduplication
- # Consider an Address model defined as follows:
- #
- # class UserAddress(models.Model):
- # user = models.ForeignKey(User)
- # name = models.CharField(max_length=255)
- # street_address = models.CharField(max_lenght=255)
- # street_address_line2 = models.CharField(max_lenght=255, blank=True, null=True)
- # zipcode = models.CharField(max_length=12, blank=True, null=True)
- # city = models.CharField(max_length=64)
- # state = models.CharField(max_length=64, blank=True, null=True)
- # country = models.CharField(max_length=2)
- # full_address = models.TextField(blank=True)
- #
- # def save(*args, **kwargs):
- # streetdata = f"{self.street_address}\n{self.street_address_line2}"
- # self.full_address = f"{streetdata}\n{self.zipcode} {self.city} {self.state} {self.country}"
- # super().save(*args, **kwargs)
- #
- # A UserAddress is saved every time the user changes something in the form, provided the form is valid.
- # The task is devising a way of removing partial addresses that are entirely a subset of the current address.
- # For example, assuming the following addresses are entered in the form(all belonging to the same user) in sequence:
- #
- # add1 = UserAddress(name="Max", city="Giventown")
- # add2 = UserAddress(name="Max Mustermann", street_address="Randomstreet", city="Giventown")
- # add3 = UserAddress(name="Max Mustermann", street_address="456 Randomstreet", city="Giventown")
- # add4 = UserAddress(name="Max Mustermann", street_address="789 Otherstreet", city="Giventown", country="NL")
- #
- # The expected result would be that only add3 and add4 are left in the DB at the end of the sequence
- """
- Approach:
- Prior to save the user's UserAddress check if any address exists.
- If not, save it and return. Otherwise get the last address and compare with current address.
- If current address is superset of last address then update last address with current address.
- Otherwise save current address as new UserAddress.
- """
- class UserAddressManager(models.Manager):
- """ manager class to help find/get useraddress instances """
- def address_count(self, user):
- return self.get_user_addresses(user).count()
- def get_last_address(self, user):
- last_address = self.filter(user=user).last()
- if last_address:
- return last_address
- return None
- class UserAddress(models.Model):
- user = models.ForeignKey(User, on_delete=models.CASCADE)
- name = models.CharField(max_length=255)
- street_address = models.CharField(max_length=255)
- street_address_line2 = models.CharField(max_length=255, blank=True, null=True)
- zipcode = models.CharField(max_length=12, blank=True, null=True)
- city = models.CharField(max_length=64)
- state = models.CharField(max_length=64, blank=True, null=True)
- country = models.CharField(max_length=2)
- full_address = models.TextField(blank=True)
- objects = UserAddressManager()
- @staticmethod
- def prepare_address_set(obj):
- """
- helper function to prepare comparable address format
- :param obj: instance of UserAddress
- :return: a set consists of units of a address
- """
- street_address_1 = obj.street_address.split() if obj.street_address else ['']
- street_address_2 = obj.street_address_line2.split() if obj.street_address_line2 else ['']
- extended_address = [obj.zipcode or '', obj.city or '', obj.state or '', obj.country or '']
- return set(street_address_1 + street_address_2 + extended_address)
- def is_superset_of(self, address):
- """
- check if current address is superset of user's old address.
- :param address: instance of UserAddress
- :return: boolean
- """
- if not address:
- return False
- _last_address = self.prepare_address_set(address)
- _current_address = self.prepare_address_set(self)
- return _current_address.issuperset(_last_address)
- def add_or_update(self):
- last_address = UserAddress.objects.get_last_address(user=self.user)
- if last_address is None:
- self.save('allow_save')
- else:
- if self.is_superset_of(last_address):
- updated_address = {
- 'street_address': self.street_address,
- 'street_address_line2': self.street_address_line2,
- 'zipcode': self.zipcode,
- 'city': self.city,
- 'state': self.state,
- 'country': self.country
- }
- UserAddress.objects.filter(id=last_address.id).update(**updated_address)
- else:
- self.save('allow_save')
- def save(self, *args, **kwargs):
- if 'allow_save' not in args:
- raise Exception('Using .save() method may cause redundancy.\n Use add_or_update method instead.')
- streetdata = f"{self.street_address}\n{self.street_address_line2}"
- self.full_address = f"{streetdata}\n{self.zipcode} {self.city} {self.state} {self.country}"
- super().save(*args, **kwargs)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement