Saturday, October 22, 2016

Re: Am I missing a design pattern? My views code somehow isn't as elegant as it should be...

I'd say you're missing a service layer.

It's known as a good practice to not have "business rules" in your views.

IP lookup should be done in your view anyway, because it's a "web
related thing". The `save_the_lead()` and email sending should be in
the service layer.

Extending a little bit and talking about pythonic code,
`IPInfo.get_result()` should not exist. Simply use the `result`
attribute or convert it to a read only property. Or, if this class
came to life just because the `get_result()` method, convert it to a
simple function.




On 21 October 2016 at 09:11, Andrew Chiw <randomshinichi4869@gmail.com> wrote:
> In my views, I have this:
> def questionnaire(request):
> def save_the_lead(cleaned_data, ipinfo):
> email = cleaned_data.pop('email', None)
> lead, created = Lead.objects.update_or_create(email=email)
> lead.q = cleaned_data
> lead.ipinfo = ipinfo
> lead.save()
> return lead
>
> form = LeadForm(request.POST or request.GET or None)
> """
> Why am I still checking for request.method == "POST"?
> if POST (valid data) to questionnaire, process it.
> if GET (valid data) to questionnaire, display it first. Even if it's all
> valid.
> """
> if request.method == "POST":
> if form.is_valid():
> i = IPInfo(get_ip(request), dummy=True)
> lead = save_the_lead(form.cleaned_data, i.get_result())
> m = Matcher()
> m.match([lead])
> e = Emailer(lead)
> e.send()
> return redirect('results', lead.id)
>
> return render(request, 'wizard/questionnaire.html', {'form': form})
>
> And IPInfo looks like this:
> import requests
> import ipdb
>
>
> class IPInfo:
> def __init__(self, ip, dummy=False):
> self.result = dict()
> if (ip and not dummy):
> response = requests.get('http://ipinfo.io/' + ip)
> self.result = response.json()
> elif (ip and dummy):
> self.result = {"ip": ip}
>
> def get_result(self):
> return self.result
>
>
> The part I'm worried about is the IPInfo lookup class and how it is used in
> the view. I know you can mock classes in tests, but maybe I should use
> dependency injection instead? or is that not needed in Python?
> If I'm missing dependency injection: I don't have control over the code that
> runs before the view, so I cannot tell it to inject another instance of
> IPInfo in there.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users+unsubscribe@googlegroups.com.
> To post to this group, send email to django-users@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/2777f9b7-ec87-4dc5-ac8f-de971860c83b%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAFmXjSDVUwCE6Tpaiv_HMRvejkrA6XvSu0zWP0tjfSsUsctHZg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment