Last time I wrote about how to do simple port & adapter in python. In this post, I will show to actually use them.
I briefly remind you what is purpose of application build in this series: user will log in, then search with keyword so he can save any search result to database for read it later.
I decided to first implement search mechanism for Reddit. This is what I will write today. Search request will be sent via GET. First, I need some form to handle this:
1 fromdjangoimportforms 2 fromdjango.confimportsettings 3 4 fromexternal_api.external_api_portimportinstantiated_port 5 6 classRedditSearchForm(forms.Form): 7 query=forms.CharField(label='search query',max_length=100) 8 9 defperform_search(self):10 search_result=instantiated_port.search(self.cleaned_data['query'])11 returnsearch_result
I defined simple form that has only one field: query which is CharField field with label. My form has one method perform_search. In this method, I import instantiated reddit port that takes instance of reddit adapter with settings from django settings module. Idealy this adapter should be singleton class. This is how it looks in reddit_adapter:
fromdjango.confimportsettings# reddit adapter class here ...instantiated_adapter=RedditAdapter(settings.REDDIT_CLIENT_ID,settings.REDDIT_CLIENT_SECRET,settings.REDDIT_USERNAME,settings.REDDIT_PASSWORD)
and in external_api_port:
from.reddit_adapterimportinstantiated_adapter# port class here ...instantiated_port=ExternalAPIPort(instantiated_adapter)
Lastly, I perform the search using the port and cleaned_data['query']. I have access to cleaned_data attribute after form validation which will be shown in the view. At the end of perform_search I return search results. These results are processed further in view:
1 fromdjango.views.generic.editimportFormView 2 fromdjango.httpimportHttpResponse 3 fromdjango.shortcutsimportrender 4 from.formsimportRedditSearchForm 5 6 classRedditSearchView(FormView): 7 template_name='search/index.html' 8 form_class=RedditSearchForm 9 success_url='add-to-favourites'10 search_result=None11 12 defget(self,request,*args,**kwargs):13 form=self.form_class(self.request.GETorNone)14 ifform.is_valid():15 self.search_result=form.perform_search()16 returnself.render_to_response(self.get_context_data(form=form))17 18 defget_context_data(self,**kwargs):19 context=super(RedditSearchView,self).get_context_data(**kwargs)20 ifself.search_result:21 context.update({22 'search_result':self.search_result,23 'sucess':True24 }25 )26 returncontext
Let begin from get method: this method is called every time get request is performed by the user. How to ensure that? I used method parameter in html:
<formmethod="get"class="form"role="form">
{{ form }}
<inputtype="submit"class="btn btn-primary"value="Search"></form>
In get method I get the form for given request.GET. On this form I call form.is_valid() to get access to cleaned_data. After that I have search results so I can insert them to html. It is done via get_context_data method when I get my basic context calling super. And if there was search performed I update context with search results and I tell my html to render them in one template.
Such updated context is taken by django and rendered to full html. Key success is present because I got if statement in html template which allows me to render results on the same page that search was performed:
{% if sucess %}
{% for item in search_result %}
<li>{{ item }}</li>
{% endfor %}
{% else %}
<!--- form here ---!>
And that basically all for search view. In next post I will take care of saving results to database. Code for this you can find under this repo.
Changes from 07.06.16:
- Moving port & adapter to it's own module
- Having only one instance of port & adapter
(Special thanks for pointing this to Mariusz)
Cover image by Creative Magic under CC0.