How to capture and modify Google Protocol Buffers in a Django view? - django

Here is a link to the proto file.
Please can someone help me understand how to make this work:
from django.views.decorators.csrf import csrf_exempt
from bitchikun import payments_pb2
#csrf_exempt
def protoresponse(request):
xpo = payments_pb2.Payment.ParseFromString(request)
t = type(xpo)
xpa = request.PaymentACK
xpa.payment = xpo.SerializeToString()
xpa.memo = u'success'
return HttpResponse(xpa.SerializeToString(), content_type="application/octet-stream")
All input appreciated :)

OK so I think I understand what is happening now. You have a system which is POSTing a serialized protobuf to your Django app, and you need to return another protobuf in response.
In Django, you can access the data from a POST in request.body. That is probably what you need to pass to ParseFromString.
You have some other errors too: you refer to request.PaymentACK, which doesn't exist - you mean payments_pb2.PaymentACK - and you never actually instantiate it. Also, you are trying to pass the serialized version of the original request protobuf to that response one, when you should be passing the actual message.
So, altogether it would look like this:
xpo = payments_pb2.Payment.FromString(request.body)
xpa = payments_pb2.PaymentACK()
xpa.payment = xpo
xpa.memo = u'success'
return HttpResponse(xpa.SerializeToString(), content_type="application/octet-stream")

Related

Documenting Django using UML

Hello Stack Overflow Community
I'm trying to document my project and I have doubled on how to translate Django Views into UML Class Diagrams.
I have to mention that I'm not using class views, just normal views.
Can you please tell me if this is ok? Do I need to let know the reader what I'm trying to achieve or it is clear what the diagram says?
Many thanks in advance for your feedback
This is the code
def index_crypto(request):
import requests
import json
#Api Call
url = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1'
headers = {'Accepts': 'application/json','X-CMC_PRO_API_KEY':'xxxxxxxxxx',}
params = {'convert' :'USD'}
api_request = requests.get(url, headers= headers,params= params) #Request Object
try:
data = json.loads(api_request.content) #JSON file containing data.
except Exception as e:
data = "Error...."
print(e)
api_assets= []
for i in data["data"]:
api_assets.append(i)
return render(request,'index_crypto.html',{'api_assets': api_assets})
By defining index_crypto as an operation in a class you would be fully compatible with UML.
Because url, headers and params have a constant value and are only visible in index_crypto you can declare them as read-only ({readOnly}) static attribute (the name is underlined) with the visibility private rather than public
For api_request (Request in your diagram ?) it is not clear to use an attribute, it is a pure local working variable as we have in operations, better to remove it for me.
If I am not wrong index_crypto returns a HttpResponse

Validate custom field with Flask-RESTPlus

I'm trying to create a custom field for validating POSTed JSON in my API using Flask-RESTPlus 0.10.1
Below is the basic setup...
from flask_restplus import fields
import re
EMAIL_REGEX = re.compile(r'\S+#\S+\.\S+')
class Email(fields.String):
__schema_type__ = 'string'
__schema_format__ = 'email'
__schema_example__ = 'email#domain.com'
def validate(self, value):
if not value:
return False if self.required else True
if not EMAIL_REGEX.match(value):
return False
return True
I like the way the above documents in Swagger UI, but I can't seem to figure out how to actually use the validate method on it.
Here's how I'm using the custom field.
Json = api.model('Input JSON', {
'subscribers': fields.List(Email),
[...]
})
#api.expect(Json) // validate is globally set to true
def post(self):
pass
I've had luck using
'subscribers': fields.List(fields.String(pattern='\S+#\S+\.\S+')) instead, but this doesn't give me the control to customize the error message, where'd I'd like it to return that the field is not of the email type.
I've also gone on and added a custom validate_payload function (found within http://aviaryan.in/blog/gsoc/restplus-validation-custom-fields.html) that I call again within my POST method (instead of api.expect). This requires me to duplicate some core functionality and call it every time in addition to api.expect to output the proper Swagger documentation and a little bit of finesse to get it to work within nested fields.
It's my understanding that this should work out of box? Am I wrong? What am I missing here?
I appreciate this is a little old but just had the same issue.
It looks like the "validate" actually sat over a python jsonschema impl, if you're still interested in digging, it's available here
That aside - you can configure restplus API to use a better formatchecker as follows: (I also validate date-time and date)
format_checker = FormatChecker(formats=["date-time", "email", "date"])
api_v1 = Api(
app, version='1.4',
title='[Anon]',
description='[Anon] API for developers',
format_checker=format_checker
)

Django syndication framework: prevent appending SITE_ID to the links

According to the documentation here: https://djangobook.com/syndication-feed-framework/
If link doesn’t return the domain, the syndication framework will
insert the domain of the current site, according to your SITE_ID
setting
However, I'm trying to generate a feed of magnet: links. The framework doesn't recognize this and attempts to append the SITE_ID, such that the links end up like this (on localhost):
<link>http://localhost:8000magnet:?xt=...</link>
Is there a way to bypass this?
Here's a way to do it with monkey patching, much cleaner.
I like to create a separate folder "django_patches" for these kinds of things:
myproject/django_patches/__init__.py
from django.contrib.syndication import views
from django.contrib.syndication.views import add_domain
def add_domain_if_we_should(domain, url, secure=False):
if url.startswith('magnet:'):
return url
else:
return add_domain(domain, url, secure=False)
views.add_domain = add_domain_if_we_should
Next, add it to your INSTALLED_APPS so that you can patch the function.
settings.py
INSTALLED_APPS = [
'django_overrides',
...
]
This is a bit gnarly, but here's a potential solution if you don't want to give up on the Django framework:
The problem is that the method add_domain is buried deep in a huge method within syndication framework, and I don't see a clean way to override it. Since this method is used for both the feed URL and the feed items, a monkey patch of add_domain would need to consider this.
Django source:
https://github.com/django/django/blob/master/django/contrib/syndication/views.py#L178
Steps:
1: Subclass the Feed class you're using and do a copy-paste override of the huge method get_feed
2: Modify the line:
link = add_domain(
current_site.domain,
self._get_dynamic_attr('item_link', item),
request.is_secure(),
)
To something like:
link = self._get_dynamic_attr('item_link', item)
I did end up digging through the syndication source code and finding no easy way to override it and did some hacky monkey patching. (Unfortunately I did it before I saw the answers posted here, all of which I assume will work about as well as this one)
Here's how I did it:
def item_link(self, item):
# adding http:// means the internal get_feed won't modify it
return "http://"+item.magnet_link
def get_feed(self, obj, request):
# hacky way to bypass the domain handling
feed = super().get_feed(obj, request)
for item in feed.items:
# strip that http:// we added above
item['link'] = item['link'][7:]
return feed
For future readers, this was as of Django 2.0.1. Hopefully in a future patch they allow support for protocols like magnet.

Using python Django, how do I return a google protobuff object as a response?

I'm ultimately aiming to create a payment request object for bitcoin, bip 70 in particular because I would like to capture a valid return address but I'm not sure of the correct method to return a protobuff response object using Django.
import payments_pb2
x = payments_pb2
x.address = 'home'
return render_to_response(x)
Any help would be appreciated :)
Thanks
Protocol buffer is a binary format. You can serve protocol buffer content from django in a similar way to serving pictures, files ...
Code example:
def protobuf_view(request):
...
x = payments_pb2
x.address = 'home'
return HttpResponse(x.SerializeToString(), content_type="application/octet-stream")

Using django haystack search with global search bar in template

I have a django project that needs to search 2 different models and one of the models has 3 types that I need to filter based on. I have haystack installed and working in a basic sense (using the default url conf and SearchView for my model and the template from the getting started documentation is returning results fine).
The problem is that I'm only able to get results by using the search form in the basic search.html template and I'm trying to make a global search bar work with haystack but I can't seem to get it right and I'm not having a lot of luck with the haystack documentation. I found another question on here that led me to the following method in my search app.
my urls.py directs "/search" to this view in my search.views:
def search_posts(request):
post_type = str(request.GET.get('type')).lower()
sqs = SearchQuerySet().all().filter(type=post_type)
view = search_view_factory(
view_class=SearchView,
template='search/search.html',
searchqueryset=sqs,
form_class=HighlightedSearchForm
)
return view(request)
The url string that comes in looks something like:
http://example.com/search/?q=test&type=blog
This will get the query string from my global search bar but returns no results, however if I remove the .filter(type=post_type) part from the sqs line I will get search results again (albeit not filtered by post type). Any ideas? I think I'm missing something fairly obvious but I can't seem to figure this out.
Thanks,
-Sean
EDIT:
It turns out that I am just an idiot. The reason why my filtering on the SQS by type was returning no results was because I didn't have the type field included in my PostIndex class. I changed my PostIndex to:
class PostIndex(indexes.SearchIndex, indexes.Indexable):
...
type = indexes.CharField(model_attr='type')
and rebuilt and it all works now.
Thanks for the response though!
def search_posts(request):
post_type = str(request.GET.get('type')).lower()
sqs = SearchQuerySet().filter(type=post_type)
clean_query = sqs.query.clean(post_type)
result = sqs.filter(content=clean_query)
view = search_view_factory(
view_class=SearchView,
template='search/search.html',
searchqueryset=result,
form_class=HighlightedSearchForm
)
return view(request)