I just starting to using odoo 11. I'm using tree inside FOLDER form, for displaying data of one2many field. The data inside tree view will be created when I click SYNC button. That button will trigger external api get method and then create appropriate data according to JSON value. When I click the button it triggered the method and successfully entered the database but when I look into the tree view, there is no value. Please help, I am stuck.
PYTHON
class GetFolder(models.Model):
_name = 'get_folders'
name_folder = fields.Text(string='Name')
email_blacklist = fields.Integer(string='Email Blacklist',store=True)
email_subscribers = fields.Integer(string='Email Subscribers',store=True)
unique_subscribers = fields.Integer(string='Unique Subscribers', store=True)
email_count = fields.Integer(string='Email', store=True)
foldersId = fields.Integer(string='FolderId', store=True)
list_folder_ids = fields.One2many(comodel_name='get_lists', string='Folder',
inverse_name='folder_lists', help="")
#api.multi
def get_lists_request(self):
res = self.env['get_lists'].search([('foldersId','=',self.foldersId)])
for record in res:
record.ensure_one()
list_url = ""
querystring = {"limit":"50","offset":"0","sort":"desc"}
headers = {
"Accept": "application/json",
"api-key": ""
}
list_response = requests.request("GET", list_url, headers=headers, params=querystring)
print(list_response.text)
list_loads = simplejson.loads(list_response.text)
_logger.warning(list_loads)
for list_load in list_loads.get("lists"):
names = list_load['name']
ids = list_load['id']
blacklist = list_load['totalBlacklisted']
subscribe = list_load['totalSubscribers']
self.env['get_lists'].sudo().create({
'id': self.id,
'name': names,
'email_subscribers': subscribe,
'email_blacklist': blacklist,
'listId' : ids,
'foldersId' : self.foldersId,
})
class GetList(models.Model):
_name = "get_lists"
name = fields.Char(string="Name")
email_subscribers = fields.Integer(string="Total Subscribers", store=True)
email_blacklist = fields.Integer(string="Total Blacklist", store=True)
folder_lists = fields.Many2one(comodel_name='get_folders', string='Lists')
foldersId = fields.Integer(string="Folder Id", related="folder_lists.foldersId", store=True)
listId = fields.Integer(string="List Id", store=True)
XML
<notebook>
<page string="Lists">
<tr style="margin-bottom:100px;">
<td><button type="object" name="get_lists_request" string="Synch" class="oe_inline oe_button btn-success"/></td>
</tr>
<field name="list_folder_ids"/>
</page>
</notebook>
EDITED VERSION
record = self.env['get_folders'].search([('id','=',self.id)])
for recx in record:
self.env['get_lists'].create({
'id': self.id,
'name': names,
'email_subscribers': subscribe,
'email_blacklist': blacklist,
'listId' : ids,
'foldersId': recx.id,
})
Yes it is succeed. Sorry for my late reply. After trying and fixing multiple times. I truly looked at your code and find the error. It is actually really simple. I forgot to input the many2one value. You really made my day. Thank you.
You need to pass the primary_key while creating the get_lists object data.
Code:
self.env['get_lists'].sudo().create({
'id': self.id,
'name': names,
'email_subscribers': subscribe,
'email_blacklist': blacklist,
'listId' : ids,
'foldersId' : self.foldersId,
'folder_lists': self and self.id // set the ref
})
Related
I have a form on my webpage for users to create a new listing. The form loads up okay but on submission an error comes up:
NoReverseMatch at /NewListing
Reverse for 'listing' with keyword arguments '{'listing': None}' not found. 1 pattern(s) tried: ['(?P<listing_id>[0-9]+)$']
The form does save the new listing and update the homepage with the new listing but I would like that once the listing is submitted, the user is taken to the new listing page and I can't seem to get that to work without this error popping up.
models.py
class Category(models.Model):
group = models.CharField(max_length=20)
def __str__(self):
return f"{self.group}"
class Listing(models.Model):
title = models.CharField(max_length=64)
description = models.TextField(max_length=64)
price = models.DecimalField(max_digits=9, decimal_places=2, validators=[MinValueValidator(0.99)])
image = models.URLField(max_length=200, blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="categories")
def __str__(self):
return f"Product: {self.title} \nDescription: {self.description} \nCurrent Price: £{self.price}\nImage: {self.image} \nCategory: {self.category}"
forms.py
class NewListingForm(forms.ModelForm):
class Meta:
model = Listing
fields = ["title", "description", "price", "image", "category"]
title = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
description = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
price = forms.DecimalField(label='Starting Bid Price (£)')
image = forms.URLField(widget=forms.URLInput(attrs={'autocomplete':'off'}))
views.py
def listing(request, listing_id):
listing = Listing.objects.get(pk=listing_id)
return render(request, "auctions/listingPage.html", {
"listing": listing
})
def newListing(request):
if request.method == "POST":
form = NewListingForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
description = form.cleaned_data['description']
price = form.cleaned_data.get('price')
image = form.cleaned_data['image']
category = form.cleaned_data['category']
listing = Listing(title=title, description=description, price=price, image=image, category=category)
form.save()
return HttpResponseRedirect(reverse("listing", kwargs={'listing': listing.id}))
else:
return render(request, "auctions/newListing.html", {
"form": form,
})
else:
form = NewListingForm()
return render(request, "auctions/newListing.html", {
"form": form
})
urls.py
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("<int:listing_id>", views.listing, name="listing"),
path("NewListing", views.newListing, name="newListing")
]
You're making a new Listing by hand from the form data, but never saving it, so it never gets an ID.
As a result, the URL that your code tries to compute as the redirection destination uses None instead of an integer for the listing ID, which blows up, because it's expecting an integer ID.
(You also save the modelform, but you don't do anything with the data that returns.)
Instead of this:
listing = Listing(title=title, description=description, price=price,image=image, category=category)
form.save()
Try just:
listing = form.save()
to let the ModelForm do all the heavy lifting and return saved object with an ID because it's in the database - that's what model forms are there for :o) https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/#the-save-method
I have a table like this:
class Mapping(db.Model):
map_id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer)
bike_id = db.Column(db.String(255))
is_active_data = db.Column(db.Boolean, default=True)
created_by = db.Column(db.String(150))
updated_by = db.Column(db.String(150))
My POST method:
def save_MapperM(adddata):
create_data = Mapping(**adddata)
db.session.add(create_data)
db.session.commit()
return dict(Successful="Successfully Created")
Route:
#test.route("/addmapper"))
class MapperV(Resource):
#staticmethod
def post():
if request.method == 'POST':
save_data = request.get_json()
try:
return jsonify(save_MapperM(save_data))
except Exception:
return jsonify({'Unsuccessful': 'Looks like you missed something !!'})
Current Code :
The current code will take only one bike_id for every request.
Requirements:
I want to take multiple bike_id's as for one user id and store it as multiple records in the table level.
Example data format coming from UI:
{ user_id: 1, bike_id: 1,2,3,4 }
The easiest solution is to modify your save_MapperM function with a cycle:
def save_MapperM(adddata):
for bike_id in adddata["bike_id"]:
item_data = adddata.copy()
item_data["bike_id"] = bike_id
create_data = Mapping(**item_data)
db.session.add(create_data)
db.session.commit()
return dict(Successful="Successfully Created")
But be careful with this function as it allows to create Mapping instances with any parameters received from the POST request. It looks like it is intended but it can lead to security issues if your Mapping class has some private attributes which should be filled only on the server side. For example the user "Mike" can send a request:
{ "user_id": 1, "bike_id": [1, 2], "created_by": "Alex", "updated_by": "Alex" }
It will cause the save_MapperM function to create instances with created_by and updated_by values set to "Alex" which may not be true. It is better to get such attributes from the session data.
So your post method may look like this (post and save_MapperM functionality combined):
def post():
request_data = request.get_json()
for bike_id in request_data.get("bike_id", []):
item = Mapping(
user_id=request_data.get("user_id"),
bike_id=bike_id,
created_by=session.get("username"),
updated_by=session.get("username"),
)
db.session.add(item)
try:
db.session.commit()
except Exception:
return jsonify({"success": False})
return jsonify({"success": True})
The next step may be implementing request JSON data validation. It is OK when you have a couple of JSON keys with a simple structure but when you need to pass lots of data you need to be sure it is correct. You can use some of the serialization/ODM libraries for this Marshmallow for example.
I use wp job manager on my website. when I tried to add listing by xmlrpc, everything is fine, but Categories and Location are empty.
Screenshot
Screenshot
My code is as below. Could you tell me what's wrong with my code?
Thanks
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import GetPosts
from wordpress_xmlrpc.methods import posts
from wordpress_xmlrpc import WordPressTerm
from wordpress_xmlrpc.methods import taxonomies
wp = Client('http://127.0.0.1/15wp/xmlrpc.php', 'admin', '123456')
# now let's create a new product
widget = WordPressPost()
widget.post_type = 'job_listing'
widget.title = 'Widgetlast02'
widget.content = 'This is the widgets description.'
widget.post_status = 'publish'
widget.custom_fields = []
widget.custom_fields.append({
'job_location': 'Newyork',
'job_listing_category': 'hotel'
})
widget.id = wp.call(posts.NewPost(widget))
The custom_fields attribute expects a list of dicts.
Within each dict, it expects values for key and value fields.
Here, key is the name of the custom field, and value is the value you want to assign to it.
Below is the snippet for your specific example.
widget.custom_fields = [
{
'key': 'job_location',
'value': 'Newyork'
},
{
'key': 'job_listing_category',
'value': 'hotel'
}
]
This is just a guess from looking at the documentation for WordPressPost in wordpress_xmlrpc:
(Emphasis mine)
class WordPressPost
Represents a post, page, or other registered custom post type in
WordPress.
id
user
date (datetime)
date_modified (datetime)
slug
post_status
title
content
excerpt
link
comment_status
ping_status
terms (list of WordPressTerms)
terms_names (dict)
custom_fields (dict)
enclosure (dict)
password
post_format
thumbnail
sticky
post_type
It expects custom_fields to be a dict - you're creating a list and then inserting a dict into that list:
widget.custom_fields = []
widget.custom_fields.append({
'job_location': 'Newyork',
'job_listing_category': 'hotel'
})
This will probably work better:
widget.custom_fields = {
'job_location': 'Newyork',
'job_listing_category': 'hotel'
}
I'm new to marshmallow and flask etc.
I'm trying to learn by creating an API that consumes a jsonified python dictionary. The dictionary contains nested dictionaries like this. It also contains a few Null items.
{
"TITLE": "XXX",
"NAME": "Mongoose",
"TIME": "0430",
"USED": null,
"DESCRIPTION": "",
"WEAPONS": {
"HEAT": "Israel",
"RADAR": "Flat",
"CONV": {
"S": true,
"N": false,
"A": false
},
},
}
I simply want to consume this back into a dictionary type. Something like this on the POST action
fields_schema = FieldSchema(many=True)
field_schema = FieldSchema()
json_data = request.get_json(force=True)
if not json_data:
return {'message': 'No input data provided'}, 400
# Validate and deserialize input
try:
data = field_schema.load(json_data)
except ValidationError as e:
return e.messages, 422
Where data would simply be a nested dictionary.
It is defining the schema class that is causing me problems.
From what I can tell, when defining the schema, marshmallow doesnt have a JSON type and when I use fields.Dict I get the following error:
{
"meta": [
"Missing data for required field."
],
"TITLE": [
"Unknown field."
etc...
I'm not sure whether I should be looking at using a nested Schema or whether I am totally over complicating things.
My fields_schema currently looks like this:
class FieldSchema(ma.Schema):
id = fields.Integer()
meta = fields.Dict(required=True)
Any pointers would be greatly appreciated
If you're going to validate the nested object, you can use Marshmallow's fields.Nested functionality.
Using their example
from marshmallow import Schema, fields, pprint
class UserSchema(Schema):
name = fields.String()
email = fields.Email()
created_at = fields.DateTime()
class BlogSchema(Schema):
title = fields.String()
author = fields.Nested(UserSchema)
user = User(name="Monty", email="monty#python.org")
blog = Blog(title="Something Completely Different", author=user)
result = BlogSchema().dump(blog)
pprint(result)
# {'title': u'Something Completely Different',
# 'author': {'name': u'Monty',
# 'email': u'monty#python.org',
# 'created_at': '2014-08-17T14:58:57.600623+00:00'}}
Your need to define a schema from the root document though. Something like
class Widget(Schema):
TITLE = fields.String()
NAME = fields.String()
# ...
WEAPONS = fields.Nested(Weapon)
class Weapon(Schema):
HEAT = fields.String()
# ...
might get you going.
I am trying to generate excel report using Odoo 10. The code is working fine and I am able to do that. But the file does'nt download on a single click. It saves the file and shows download link on wizard. But I dont want this extra step. I want the file to be downloaded in single click. I am sharing my working code below here. Please have a look and suggest me what should be added to make it work in a single click.
xml code:
<div state="get">
<group>
<field name="name" colspan="4" invisible="1"/>
<field name="report" filename="name" colspan="4"/>
</group>
</div>
<button name="generate_xls_report" string="Export XLS" type="object" class="oe_highlight" />
Python Code:
from odoo import fields, models, api, _
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
import xlwt
import base64
import cStringIO
from datetime import datetime
class CasesWizard(models.TransientModel):
_name = "cases.wizard"
_description = "Cases wizard"
case_id = fields.Many2one('project.project', string='Cases')
event_id = fields.Many2one('calendar.event', string='Events')
company_id = fields.Many2one('res.company', string='company id', readonly=True,default=lambda self: self.env.user.company_id.id)
lawyer_id = fields.Many2one('res.users', string='Lawyers')
#partner_id = fields.Many2one('res.partner', string='Clients')
date_from = fields.Date(string='Start Date')
date_to = fields.Date(string='End Date')
state = fields.Selection([('choose', 'choose'), ('get', 'get')],default='choose')
report = fields.Binary('Prepared file', filters='.xls', readonly=True)
name = fields.Char('File Name', size=32)
#api.multi
def generate_xls_report(self):
self.ensure_one()
wb1 = xlwt.Workbook(encoding='utf-8')
ws1 = wb1.add_sheet('Case Event Details')
fp = cStringIO.StringIO()
# Here all excel data and calculations
wb1.save(fp)
out = base64.encodestring(fp.getvalue())
self.write({'state': 'get', 'report': out, 'name':'event_details.xls'})
return {
'type': 'ir.actions.act_window',
'res_model': 'cases.wizard',
'view_mode': 'form',
'view_type': 'form',
'res_id': self.id,
'views': [(False, 'form')],
'target': 'new',
'name': 'Event Details Report'
}
You can achieve that using a web controller.
Add the following method to the wizard model:
#api.multi
def generate_xls_report(self):
self.ensure_one()
return {
'type': 'ir.actions.act_url',
'url': '/web/binary/download_xls_document?model=cases.wizard&id=%s&filename=event_details.xls' % (
self.id),
'target': 'new',
}
Then create the web controller:
class Binary(http.Controller):
#http.route('/web/binary/download_xls_document', type='http', auth="public")
#serialize_exception
def download_xls_document(self, model, id, filename=None, **kw):
Model = request.registry[model]
cr, uid, context = request.cr, request.uid, request.context
wb1 = xlwt.Workbook(encoding='utf-8')
ws1 = wb1.add_sheet('Case Event Details')
fp = cStringIO.StringIO()
# Here all excel data and calculations
wb1.save(fp)
filecontent = fp.getvalue()
if not filecontent:
return request.not_found()
else:
if not filename:
filename = '%s_%s' % (model.replace('.', '_'), id)
return request.make_response(filecontent,
[('Content-Type', 'application/octet-stream'),
('Content-Disposition', content_disposition(filename))])
This should generate an empty xls file.