How to enable object type button? - object

My python function returns an action url after which my button disables. OpenERP adds an attribute disable="disable" to my button . I don't want to disable button.
My code is
<button name="play_file" type="object" string="Play or download" />
def play_file(self, cr, uid, ids, context=None):
res = self.read(cr, uid, ids, ['file_name'], context=context)
file_name = res[0]['file_name']
return{
'type': 'ir.actions.act_url',
'url':'ftp://test.claudion.com:123/'+file_name,
# 'target': 'new',
}

Related

How do I display error messages when I am not looping over form fields in Django templates?

My forms are not showing the error messages when I try to submit an empty form but I can see the errors while looping over the field errors in views.py. How do I overcome this problem?
the template (Updated):
{% block formcontent %}
{{form.non_field_errors}}
<div class="row">
<div class="col">
{{form.username.label_tag}} {{form.username}} {{form.username.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.first_name.label_tag}} {{form.first_name}} {{form.first_name.errors|striptags}}
</div>
<div class="col">
{{form.last_name.label_tag}} {{form.last_name}} {{form.last_name.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.email.label_tag}} {{form.email}} {{form.email.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.location.label_tag}} {{form.location}} {{form.location.errors|striptags}}
</div>
<div class="col">
{{form.designation.label_tag}} {{form.designation}} {{form.designation.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.password1.label_tag}} {{form.password1}} {{form.password1.errors|striptags}}
</div>
<div class="col">
{{form.password2.label_tag}} {{form.password2}} {{form.password2.errors|striptags}}
</div>
</div><br>
{% endblock formcontent %}
Edit 1:
(Updated)
class MyRegistrationForm(UserCreationForm):
password1=forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
password2=forms.CharField(label='Confirm Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model=MyRegistration
fields=['username', 'first_name', 'last_name', 'email', 'location', 'designation']
widgets={
'username':forms.TextInput(attrs={'class':'form-control'}),
'first_name':forms.TextInput(attrs={'class':'form-control'}),
'last_name':forms.TextInput(attrs={'class':'form-control'}),
'email':forms.EmailInput(attrs={'class':'form-control'}),
'location':forms.Select(attrs={'class':'form-select'}),
'designation':forms.TextInput(attrs={'class':'form-control'}),
}
def clean_username(self):
username = self.cleaned_data.get('username')
if not username:
raise ValidationError('Username is required!')
else:
try:
MyRegistration.objects.get(username=username)
raise ValidationError('This username already exists!', code='username_exists')
except MyRegistration.DoesNotExist:
pass
return username
def clean_email(self):
email=self.cleaned_data.get('email')
if not email:
raise ValidationError('Email is required!')
else:
try:
MyRegistration.objects.get(email=email)
raise ValidationError('This email already exists!', code='email_exists')
except MyRegistration.DoesNotExist:
pass
return email
def clean_first_name(self):
first_name=self.cleaned_data.get('first_name')
if not first_name:
raise ValidationError('First-name is required!')
return first_name
def clean_last_name(self):
last_name=self.cleaned_data.get('last_name')
if not last_name:
raise ValidationError('Last-name is required!')
return last_name
def clean_location(self):
location=self.cleaned_data.get('location')
if not location:
raise ValidationError('Location is required!')
return location
def clean_designation(self):
designation=self.cleaned_data.get('designation')
if not designation:
raise ValidationError('Designation is required!')
return designation
I really have no idea what is wrong with my codes in template. I have checked, the Django documentation suggests the same way to approach such scenarios where the forms are not looped over.
Edit 2:
models.py:
class MyRegistration(AbstractBaseUser, PermissionsMixin):
location_list=[
('Solapur', 'Solapur'),
('Dhule', 'Dhule'),
('Other', 'Other'),
]
username=models.CharField(max_length=10, unique=True)
email=models.EmailField(unique=True)
first_name=models.CharField(max_length=150)
last_name=models.CharField(max_length=150)
location=models.CharField(max_length=10, choices=location_list, default=None)
designation=models.CharField(max_length=70)
is_active=models.BooleanField()
is_staff=models.BooleanField(default=False)
start_date=models.DateTimeField(default=timezone.now)
last_login=models.DateTimeField(null=True)
USERNAME_FIELD='username'
REQUIRED_FIELDS=['email', 'first_name', 'last_name', 'location', 'designation']
objects=FirstManager()
def __str__(self):
return self.first_name
views.py:(Updated)
def signup(request):
print('1')
if request.user.is_authenticated:
print('2')
if request.method=='POST':
print('3')
if request.POST.get('password1')==request.POST.get('password2'):
print('4')
fm=MyRegistrationForm(request.POST)
for field in fm:
print("Field Error:", field.name, field.errors)
if fm.is_valid():
print('6')
fm.save()
messages.success(request, 'Registered successfully!!')
fm=MyRegistrationForm()
print('7')
cur_user=request.user
return render(request, 'account/signup.html', {'form':fm, 'cur_user':cur_user})
else:
fm=MyRegistrationForm()
cur_user=request.user
return render(request, 'account/signup.html', {'form':fm, 'cur_user':cur_user})
else:
return HttpResponseRedirect('/')
When you raise ValidationError in the clean method, these errors get added to the non_field_errors attribute on the form. This is why nothing gets rendered when using form.email.errors and other errors attributes on particular fields.
You should render the form.non_field_errors before you render your form, so you can see those errors, too.
However, to solve your issue, I would rather go with the option of splitting the validation of each field into particular methods clean_<field_name>. For example for username field:
def clean_username(self):
username = self.cleaned_data.get('username')
if not username:
raise ValidationError('Username is required!')
else:
try:
un=MyRegistration.objects.get(username=self.instance.username)
raise ValidationError('This username already exists!')
except MyRegistration.DoesNotExist:
pass
# Make sure you return the value of the data in
# the clean_<field_name> methods
return username
And so on for other fields, too. Doing just this should fix your code, but here are some other recommendations:
Use codes when raising ValidationErrors. E.g.: raise ValidationError('This username already exists', code='username_exists')
Check out the django-crispy package, it can handle the HTML rendering of forms with minimal code
You can set constraints in the models for unique fields (e.g. username) and required fields. This further prevents users who are not adding data with your form (e.g. admin) to add duplicate usernames or null values. This would also mean that a lot of your custom validation code would be unnecessary.
EDIT #1:
The use of instance to get the values from the submitted form is wrong. Since this form is used exclusively for create purposes as registration is creation of a new user, instance will always be empty. instance is only filled with data when you're updating a model instance.
You should replace the uses of instance with getting the form data from self.cleaned_data dict.
For example:
# Instead of:
username = self.instance.username
# Use:
username = self.cleaned_data.get('username')
EDIT #2:
After the author added the view code.
The issue might be in your view code. Also, there is no need to comparing password1 and password2 as the UserCreationForm already does that for your.
The core issue is that if your form is invalid, you need to re-render that same form, not create another instance. I propose the following update:
def signup(request):
print('1')
if request.user.is_authenticated:
print('2')
if request.method=='POST':
print('3')
form = MyRegistrationForm(request.POST)
if form.is_valid():
print('4')
form.save()
messages.success(request, 'Registered successfully!!')
# If you do this, you always render the empty form
# without the errors
# fm=MyRegistrationForm()
print('7')
cur_user=request.user
return render(
request, 'account/signup.html',
{'form': form, 'cur_user':cur_user}
)
else:
form = MyRegistrationForm()
cur_user=request.user
return render(
request, 'account/signup.html',
{'form':form, 'cur_user':cur_user}
)
else:
return HttpResponseRedirect('/')
Some other recommendations:
You probably don't need to check if the user is authenticated if this is registration view. How can the new users create an account? However, if this is needed probably the #login_required decorator works better for this.
On success, you need to redirect to the success URL. Don't use render for success scenarios, only when handling the GET method or when you need to re-render the form to display validation errors.

I have a mistake like this "AttributeError at /uz/account/update/ 'str' object has no attribute '_meta' "

The above error occurs when you click the save button,but in the docs I think I am putting in the correct parameters.
Where that bit of code is in my views.py:
class AllUserUpdate(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
alluser = CustomUser.objects.get(username=self.request.user.username)
form = CustomUserForm(instance=alluser)
context = {'form':form}
return render(request, 'account/AllUserAccount.html', context)
def post(self, request, *args, **kwargs):
form = CustomUserForm(self.request.POST, self.request.FILES, instance=self.request.user.username)
if form.is_valid():
form.save()
messages.info(self.request, "Your are change successfully created!")
context = {'form': form}
return redirect('all_user_update')
This is what my template looks like:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<h3>Full name: {{ request.user.full_name }}</h3>
{{ form.as_p }}
<input type="submit" class=" btn btn-primary" value="Save">
</form>
forms.py:
class CustomUserForm(UserCreationForm):
password1 = forms.CharField(widget=forms.PasswordInput(
attrs={'class': 'form-control mt-2', 'name': 'password1', 'placeholder': 'enter the password...'}))
password2 = forms.CharField(widget=forms.PasswordInput(
attrs={'class': 'form-control mt-2', 'name': 'password2', 'placeholder': 'Repeat the password...'}))
class Meta:
model = CustomUser
fields = ('full_name', 'email', 'user_type', 'phone', 'password1', 'password2', 'username')
widgets = {
'full_name': forms.TextInput(attrs={'class': 'form-control mt-2', 'name': 'full_name'}),
'username': forms.TextInput(attrs={'class': 'form-control mt-2', 'name': 'username'}),
'email': forms.EmailInput(attrs={'class': 'form-control mt-2', 'name': 'email'}),
'phone': forms.TextInput(attrs={'class': 'form-control mt-2', 'name': 'phone'}),
'user_type': forms.Select(attrs={'class': 'form-control mt-2', 'name': 'user_type'}),
}
I want users to change their personal pages
On this line:
form = CustomUserForm(self.request.POST, self.request.FILES, instance=self.request.user.username)
you're passing a string (str) as the form's instance. That's not what the instance argument expects; it expects a Model instance (like you correctly pass it in the get method, a few lines before).
Pass the CustomUser you want to be updated as the instance, instead, for example:
customuser = CustomUser.objects.get(username=request.user.username)
form = CustomUserForm(request.POST, instance=customuser)

Value in tree view inside form not appearing Odoo 11

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
})

How can I add a popup from the Import Button in Odoo 13?

I'm trying to add a popup form connected to a wizard when importing leads through the standard import funcionality. I've attmpted to override both the do() method in the base_import.import and override the load() method on crm.lead to trigger the same popup. I have included the load() version of the method below. Is there a way to do this or would I be best trying to add an option under "Map your columns to import" or just create a config option and skip modifying the import function all together.
#api.model
def load(self, fields, data):
if not ('assignment_selected' in self.env.context and self.env.context['assignment_selected']):
import_vals = {
'fields': fields,
'data': data,
}
view_id = self.env.ref('mdlu_lead_assignment_ext.view_crm_import_wizard').id
return {
'name': _('Lead Import Assignment Options'),
'type': 'ir.actions.act_window',
'res_model': 'crm.import.wizard',
'view_mode': 'form',
'views': [(view_id, 'form')],
'target': 'new',
'context': dict(self.env.context, import_vals=import_vals),
}
recs = super(Team, self).load(fields, data)
return rec

How to generate excel report using wizard in Odoo 10, in a single click

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.

Resources