Using pytest to test a DRF post - api

I'm searching for some examples to test my drf api with pytest. I made some fixtures to create user and connect. Does someone have a guide/reference to implement a POST test? It is for a product with the following fields: name, description, price and category.
For status_code test I wrote:
#pytest.fixture
def user():
username = 'test'
password = 'test'
User.objects.user(username=username, password=password)
#pytest.fixture
#pytest.mark.django_db
def client(user):
token = Token.objects.get(user__username='test')
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token ' + token.key)
return client
#pytest.mark.django_db
def test_status(client):
resp = client.get('/myapi/api/product/')
assert resp.status_code == 200
And it's ok.
For test a product create, I tried this:
#pytest.mark.django_db
def test_create(client):
resp = client.post(
'/myapi/api/product/',
{
'name': 'teste1',
'description': "Teste1",
'price': 3.50,
'category': 1
},
format='json'
)
assert resp.status_code == 201
But I receive 400.

Related

Django restframework SerializerMethodField background work

I am writing a project in Django with rest framework by using SerializerMethodField. This method makes queries for every row to get data, or View collects all queries and send it to DB? Django can make it as one joint query?
class SubjectSerializer(serializers.ModelSerializer):
edu_plan = serializers.SerializerMethodField(read_only=True)
academic_year_semestr = serializers.SerializerMethodField(read_only=True)
edu_form = serializers.SerializerMethodField(read_only=True)
def get_edu_plan(self, cse):
return cse.curriculum_subject.curriculum.edu_plan.name
def get_academic_year_semestr(self, cse):
semester = cse.curriculum_subject.curriculum.semester
return {'academic_year': semester.academic_year, 'semester': semester}
def get_edu_form(self, cse):
return cse.curriculum_subject.curriculum.edu_form.name
class Meta:
model = CurriculumSubjectEmployee
fields = [
'id',
'name',
'edu_plan',
'academic_year_semestr',
'edu_form'
]
class SubjectViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = SubjectSerializer
def get_queryset(self):
contract = self.request.user.employee.contract
if contract is None:
raise NotFound(detail="Contract not found", code=404)
department = contract.department
cses = CurriculumSubjectEmployee\
.objects\
.filter(curriculum_subject__department=department)
return cses

What does the path /shop/get_suggest mean?

I found a module that autocomplete search in a Website e-commerce with high-light match words and image. But I did not really understand what each command do .
Can you please explain to me how this code work, and why they did /shop/get_suggest?
class WebsiteSale(http.Controller):
#http.route(['/shop/get_suggest'], type='http', auth="public", methods=['GET'], website=True)
def get_suggest_json(self, **kw):
query = kw.get('query')
names = query.split(' ')
domain = ['|' for k in range(len(names) - 1)] + [('name', 'ilike', name) for name in names]
products = request.env['product.template'].search(domain, limit=15)
products = sorted(products, key=lambda x: SequenceMatcher(None, query.lower(), x.name.lower()).ratio(),
reverse=True)
results = []
for product in products:
results.append({'value': product.name, 'data': {'id': product.id, 'after_selected': product.name}})
return json.dumps({
'query': 'Unit',
'suggestions': results
})
This controller function will be activated when you load page your_domain/shop/get_suggest.
The function just searches for products with similar name of the query given in the search.
Please go through this documentation to learn basics of building a website

How to display external information on Odoo 11?

I'm working on Weather application using Odoo11, I have a Python script that fetches weather information from this API: https://openweathermap.org/api
The script works fine but I have no idea how to integrate it with Odoo.
Can you give guidelines about how to achieve this, for example how to show this information in a form view, tree or Kanban?
Any example will be very helpful for me.
If you only want to show some text that´s always updated you can use a computed field
from odoo import api
weather = fields.Text( # this can be an image or any other field type
string='Weather',
compute='_compute_weather'
)
#api.depends() # leave this empty, so this is executed always when the view with this field is loaded
def _compute_weather(self):
for record in self:
# retrieve the weather information here
record.weather = weather_information # assign the weather information to the variable
Show it in a form view as any other field
<field name="weather" />
Note: If you want to store the information on the database you can just create a button or a atomate task, for instance, to store or update the values in the fields (without compute method).
Note2: Check the source code of the user_weather_map module from Cybrosis, it may be helpful
You can use the module User Weather Notification.
This module uses external API.
def get_weather(self, user_id):
rec = self.env['user.weather.map.config'].search([('user_id', '=', user_id)], limit=1)
if rec:
weather_path = 'http://api.openweathermap.org/data/2.5/weather?'
if rec.u_longitude and rec.u_latitude:
params = urllib.urlencode(
{'lat': rec.u_latitude, 'lon': rec.u_longitude, 'APPID': rec.appid})
elif rec.city:
params = urllib.urlencode(
{'q': rec.city, 'APPID': rec.appid})
else:
return {
'issue': 'localization'
}
url = weather_path + params
try:
f = urllib.urlopen(url)
except Exception:
f = False
if f:
ret = f.read().decode('utf-8')
result = json.loads(ret)
if result:
if "cod" in result.keys():
if result['cod'] == 200:
city = False
city2 = False
if "name" in result.keys():
city = result['name']
if not city:
if rec.method == 'address':
city = rec.city
if rec.method == 'address':
city2 = rec.city
temp = pytemperature.k2c(result['main']['temp'])
min_temp = pytemperature.k2c(result['main']['temp_min'])
max_temp = pytemperature.k2c(result['main']['temp_max'])
weather_rec = self.search([('user_id', '=', rec.user_id.id)])
now_utc = datetime.now(timezone('UTC'))
user_list = self.env['res.users'].search([('id', '=', user_id)])
if user_list.partner_id.tz:
tz = pytz.timezone(user_list.partner_id.tz)
now_pacific = now_utc.astimezone(timezone(str(tz)))
current_time = now_pacific.strftime('%d %B %Y, %I:%M%p')
vals = {
'date_weather_update': current_time,
'name': city,
'city': city2,
'user_id': user_id,
'weather': result['weather'][0]['main'],
'description': result['weather'][0]['description'],
'temp': temp,
'pressure': result['main']['pressure'],
'humidity': result['main']['humidity'],
'min_temp': min_temp,
'max_temp': max_temp,
}
if weather_rec:
weather_rec.write(vals)
return {
'issue': ''
}
else:
weather_rec.create(vals)
return {
'issue': ''
}
else:
return {
'issue': 'timezone'
}
else:
return {
'issue': 'localization'
}
else:
return {
'issue': 'bad_request'
}
else:
return {
'issue': 'internet'
}
else:
return {
'issue': 'config'
}
This is the code that I use in that module. you can just convert it into odoo11.
Thank you.

Get some extra details from another page for each list item using Scrapy framework

I have managed to parse the list of advertisements, put some information in AdvertItem and load this item using AdvertLoader. But I could not figure out how I can get some extra information about each advertisement from item page details, put this additional information in the same AdvertItem object and then load the item with all information using AdvertLoader.
class AdvertLoader(ItemLoader):
default_input_processor = MapCompose(unicode.strip, remove_tags)
default_output_processor = Join()
class AdvertSpider(scrapy.Spider):
name = "adverts"
start_urls = [
"http://blablaadverts.com/",
]
adverts_list_xpath = '//table[#class="object-list-table"]/tbody/tr[#class="object-type-apartment"]'
advert_item_fields = {
'id': './#id',
'link': './/td[#class="object-name"]/h2[contains(#class, "object-title")]/a/#href',
'status': 'normalize-space(.//td[contains(#class, "object-media")]/div/p/a/span[contains(#class, '
'"sold-overlay-list")]/span/text())',
'state': './/td[#class="object-name"]/h2[contains(#class, "object-title")]/a/text()',
'city': './/td[#class="object-name"]/h2[contains(#class, "object-title")]/a/text()',
'zone': './/td[#class="object-name"]/h2[contains(#class, "object-title")]/a/text()',
'address': './/td[#class="object-name"]/h2[contains(#class, "object-title")]/a/text()',
'rooms': './/td[contains(#class, "object-rooms")]/text()',
'area': 'normalize-space(.//td[contains(#class, "object-m2")]/text())',
'price': 'normalize-space(.//td[contains(#class, "object-price")]/p/text())',
}
advert_details_xpath = '//table[contains(#class, "object-data-meta")]/tbody/tr'
advert_item_details_fields = {
'floor': './/td/text()',
'built_in_year': './/td/text()',
'condition': './/td/text()',
'ownership': './/td/text()',
'energy_level': './/td/text()',
}
contact_name = '//div[contains(#class, "object-article-contact")]/p[#class="fn"]/text()'
next_page = '//li[contains(#class, "next")]/a/#href'
def parse(self, response):
selector = Selector(response)
for advert in selector.xpath(self.adverts_list_xpath):
loader = AdvertLoader(AdvertItem(), selector=advert)
for field, xpath in self.advert_item_fields.iteritems():
loader.add_xpath(field, xpath)
# This request is not working as I expect.
yield scrapy.Request("http://blablaadverts.com/index.htmlnr=55&search_key=ca41231a29d2ab921aed02e864152c0e",
callback=self.parse_page2, meta={'loader': loader})
yield loader.load_item()
next_page = response.xpath(self.next_page).extract_first()
if next_page is not None:
next_page = response.urljoin(next_page)
yield Request(next_page, callback=self.parse)
def parse_page2(self, response):
selector = Selector(response)
loader = response.meta['loader'] # type: AdvertLoader
loader.selector = selector
loader.add_xpath('contact_name', self.contact_name)
# yield loader.load_item()
Below code saves only information about each advertisement without extra details from second item details page.
Function parse_page2() is working if I run it separately from parse() function.
How can I collect all information and only then load my AdvertItem object in loader?
I am not sure I get you correctly or not.
But change this part of code
# This request is not working as I expect.
yield scrapy.Request("http://blablaadverts.com/index.htmlnr=55&search_key=ca41231a29d2ab921aed02e864152c0e",
callback=self.parse_page2, meta={'loader': loader})
yield loader.load_item()
to
# This request is not working as I expect.
scrapy.Request("http://blablaadverts.com/index.htmlnr=55&search_key=ca41231a29d2ab921aed02e864152c0e",
callback=self.parse_page2, meta={'loader': loader})
loader.load_item()
And then yield in this function when all information is available.
def parse_page2(self, response):
selector = Selector(response)
loader = response.meta['loader'] # type: AdvertLoader
loader.selector = selector
loader.add_xpath('contact_name', self.contact_name)
yield loader.load_item()

Run a report from a wizard

I have a wizard with a button. On button action I want to run a report and leave the PDF on the server. I have the above code fragment that creates a report with web service. But in a wizard context I have normally only the uid (I think).
What will be the equivalent way to get the report to disk in a wizard ?
def reportToDisk(self, cr, uid, ids, context=None):
dbname = 'db'
username = 'user'
pwd = 'pass'
model = 'sale.order'
report_name = 'doc.sale'
sock_common = xmlrpclib.ServerProxy ('http://localhost:8069/xmlrpc/common')
uid = sock_common.login(dbname, username, pwd)
sock = xmlrpclib.ServerProxy ('http://localhost:8069/xmlrpc/object')
ids = sock.execute(dbname, uid, pwd, model, 'search',[])[0:1]
sock_report = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/report')
id_report = sock_report.report(
dbname, uid, pwd, report_name, ids,{'model': model, 'id': ids[0], 'report_type':'pdf'}
)
cont = True
while cont:
report = sock_report.report_get(dbname, uid, pwd, id_report)
cont = not report['state']
string_pdf = base64.decodestring(report['result'])
file_pdf = open('/home/arch-in/file.pdf','w')
file_pdf.write(string_pdf)
file_pdf.close()
Return the report action on your button click(It can be wizard button or view button, it just works with button click return) like following:
def btn_clik_action(self, cr, uid, ids, context=None):
if context == None:
context = {}
value = {
'type': 'ir.actions.report.xml',
'report_name':'report.name.(servicename)',
'datas': {
'model':'model.name',
'id': ids and ids[0] or False,
'ids': ids and ids or [],
'report_type': 'pdf'
},
'nodestroy': True
}
Just returning the report action will give you file of the report which basically you don't need to write or anything.
Thank YOu