skip to Main Content

I want to add these fields to my Store Model, but i wanna include logic that if Let’s say WooCoomerce was chosen as a StoreType, i want Access_Token not to be Required. Also when i Choose either Shopify/Shopper i want Consumer_key and Consumer_secret not to be required. Do you have any idea how to get around that?

    StoreType = models.CharField(blank=True, choices=Storetypes.choices, max_length=12)
    Api_Url = models.CharField(blank=True)
    Access_Key = models.CharField(blank=True, max_length=100)
    Consumer_Key = models.CharField(blank=True, max_length=100)
    Consumer_Secret = models.CharField(blank=True, max_length=100)

2

Answers


  1. You can’t make this type of logic on database layer. For this case you can move this logic to a classmathod of the model to satisfy the dry-pattern. Also set the fields to nullable in your model.

    Something like so:

    class YourClass(models.Model):
        store_type = models.CharField(blank=True, choices=Storetypes.choices, max_length=12)
        api_url = models.CharField(blank=True,)
        access_key = models.CharField(blank=True, max_length=100, null=True)
        consumer_key = models.CharField(blank=True, max_length=100, null=True)
        consumer_secret = models.CharField(blank=True, max_length=100, null=True)
    
        @classmethod
        def save_woo_commerce(cls, api_url, consumer_key, consumer_secret):
            return YourClass.objects.create(
                store_type="woo_commerce",
                api_url=api_url,
                consumer_key=consumer_key,
                consumer_secret=consumer_secret
            )
    
        @classmethod
        def save_shopify(cls, api_url, access_key):
            return YourClass.objects.create(
                store_type="shopify",
                access_key=access_key,
                api_url=api_url,
            )
    

    With that your logic is still connected to the model and you can reuse instance creation on multiple places of your code.

    Login or Signup to reply.
  2. At some point those fields are going to be inputs.

    If they come in through a form, it’s a matter of using a clean method that generates errors for invalid combinations, or checking at the view level. A pattern I have found myself using quite often with class-based views (based on FormView) is like the following. Key points: form.add_error to convert a valid form into an invalid one, and return self.form_invalid(form) to show the user what needs to be fixed.

    def form_valid( self, form)
        store_type = form.Cleaned_data['store_type']
        api_url = form.cleaned_data[' ... ']
        ...
        # now, further checks
        ...
        errors = False
        if store_type == SHOPIFY or store_type == SHOPPER:
             # consumer_key and consumer secret not required
             consumer_key = consumer_secret = ''
             # but presumably, api_url and access_key are mandatory
             if api_url == '':
                 # get human representation of store_type
                 human_store_type = ...
                 form.add_error('api_url', f'API Url is required whenever store type is "{human_store_type}"' ) 
                 errors = True
             if access_key == '':
                 ... # similar, but add error to access_Key field
    
             # maybe validate that the api_url and access_key actually work
             # and add an error if they don't work together?
             if not check_valid( api_url, access_key):
                 errors = True
                 form.add_error( None, 'api_url and access_key do not work with each other') # non-field error
    
             if errors:
                 return self.form_invalid( form)
    
        elif store_type == ...
            ...
    
        # OK we have a completely valid set of inputs
        # get the object (if its a ModelForm)
        store  = form.save( commit = False)
        store.api_url = api_url
        ... # and the other fields we extra-validated
        store.save()
    
        return redirect( ...)
    

    It’s possible to subclass the save method on your object to cause an exception if any mandatory fields are blank, but this can be more trouble than its worth. If there is one or few views through which these fields can be set, then check there. Sometimes, it’s even useful to save an incomplete object: give it a Boolean is_complete field. For example, it may be necessary for a human supervisor to authorize the addition of a new store.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search