Override base class field in Odoo - attributes

I have to make Purchase Order Line as editable in Odoo 8. Currently, the field order_line in Purchase.Order Model has modifier as below:
'order_line': fields.one2many('purchase.order.line', 'order_id', 'Order Lines',
states={'approved':[('readonly',True)],
'done':[('readonly',True)]},
copy=True)
So the states is readonly if approved or done. I want to remove this. I tried with below:
<field name="order_line" position="attributes">
<attribute name="readonly">0</attribute>
</field>
Also,
<xpath expr="//field[#name='order_line']" position="attributes">
<attribute name="readonly">0</attribute>
</xpath>
But It does not work.
Please help
Thanks,
UPDATE:
class PurchaseOrder(models.Model):
'''
classdocs
'''
_name = 'purchase.order'
_inherit = 'purchase.order'
total_cases = fields.Integer('Total Cases', default=None)
appointment_number = fields.Char('Appointment Number', default=None)
order_line = fields.One2many('purchase.order.line', 'order_id', 'Order Lines', copy=True)
I overrided the field order_line as above, But nothing happens

Just inherit from the model and define the field again to override it, then you can remove states totally
from openerp import fields, models
class custom_purchase_order(models.Model):
_inherit = 'purchase.order'
order_line = fields.One2many('purchase.order.line', 'order_id', 'Order Lines', states={}, copy=True)

Related

'MoneyField' object has no attribute 'serialize'

I have model Product with field MoneyField in /products/models.py
class Product(SeoModel, ModelWithMetadata, PublishableModel):
name = models.CharField(max_length=128)
currency = models.CharField(
max_length=settings.DEFAULT_CURRENCY_CODE_LENGTH,
default=settings.DEFAULT_CURRENCY,
)
price_amount = models.DecimalField(
max_digits=settings.DEFAULT_MAX_DIGITS,
decimal_places=settings.DEFAULT_DECIMAL_PLACES,
)
price = MoneyField(amount_field="price_amount", currency_field="currency")
My views.py is:
from .models import Product
from .serializers import ProductListSerializer
from rest_framework import generics
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductListSerializer
and serializers.py:
from rest_framework import serializers
from .models import Product
class ProductListSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['name', 'id']
and when i go to url i have error:
AttributeError at /ru/products/api/
'MoneyField' object has no attribute 'serialize'
Request Method: GET
Request URL: http://127.0.0.1:8000/ru/products/api/
Django Version: 2.2.6
Exception Type: AttributeError
Exception Value:
'MoneyField' object has no attribute 'serialize'
Can you help me? Thank you!
DRF's ModelSerializer assumes fields that are on the model extend django.db.models.fields.Field, which MoneyField does not. This is a problem when ModelSerializer is collecting fields:
# rest_framework.utils.model_meta._get_fields
def _get_fields(opts):
fields = OrderedDict()
for field in [field for field in opts.fields if field.serialize and not field.remote_field]:
fields[field.name] = field
return fields
You can fix the problem by subclassing MoneyField:
from django_prices.models import MoneyField as BaseMoneyField
class MoneyField(BaseMoneyField):
serialize = True
This will probably lead to your next problem ;)

how to convert this model into non editable model in admin of django?

I create a model but I need a non-editable model. When I visit the model it's just displaying text, not giving any option of update the record in admin panel.
model.py
class Contact(models.Model):
name = models.CharField(max_length=160)
email = models.EmailField()
subject = models.CharField(max_length=255)
message = models.TextField()
def __str__(self):
return self.subject
While searching I get information about readonly but I do not still understand how to use it.
There are two ways to do this. One, make editable=False for all the fields, then it will not be edible anywhere(modelform and adminsite):
class Contact(models.Model):
name = models.CharField(max_length=160, editable=False)
email = models.EmailField(editable=False)
subject = models.CharField(max_length=255, editable=False)
message = models.TextField(editable=False)
Two, in adminsite, use readonly_fields:
class ContactAdmin(admin.ModelAdmin):
readonly_fields = ('name', 'email', 'subject', 'message')
admin.site.register(Contact, ContactAdmin)

NOT NULL constraint failed: product_product.author_id

When I am going to post objects in the postman I am getting this error
NOT NULL constraint failed: product_product.author_id
I included Basic Auth in the Authorization section anyway it gives me error.
models.py
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
brand = models.CharField(max_length=200)
rating = models.PositiveSmallIntegerField(default=0)
description = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
serializers.py
class ProductSerializer(serializers.HyperlinkedModelSerializer):
category = serializers.SlugRelatedField(queryset=Category.objects.all(), slug_field='name')
author = serializers.ReadOnlyField(source='author.username')
class Meta:
model = Product
fields = ['id', 'url', 'category', 'name', 'brand', 'rating', 'description', 'price']
Why Not Null constraint happens? how can I solve this? Thanks in advance!
I think you should add models.create_all() in Models.py to create the database
The error happens simply because your create request is not providing a value for
author attribute of a product.
# models.py
class Product(models.Model):
....
author = models.ForeignKey(User, on_delete=models.CASCADE)
so in order to resolve this issue totally depends on your business logic,
Is it important for a product to have an Author?
[NO] ==> then just make the foreign key null=True, blank=True
[YES] ==> Then you need to modify your creation logic a lil bit.
Is the author of a product is the same one who created it?
[YES], then this can easily be done by overriding your serializer's create method
....
# Inside you serializer
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
return super().create(validated_data)
[NO], You have to make the serializer accept writes on author field.
A small note, your ProductSerializer Meta class's fields attribute, doesn't include 'author', make sure it is added there too.

DRF use nested serializer to create key object instead of array

Context
Say we take this example from the DRF relations guide.
# models.py
class Album(models.Model):
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
class Meta:
unique_together = ('album', 'order')
ordering = ['order']
def __str__(self):
return '%d: %s' % (self.order, self.title)
Using a serializer will get us this output
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
Will get us this output:
{
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': [
'1: Sunflower',
'2: Whitetail',
'3: Dinosaur Act',
...
]
}
Question
How can i use the serializer to get the output like this:
{
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': {
1: {order: 1, title: 'Sunflower'},
2: {order:2, title: 'Whitetail'},
3: {order:3, title: 'Dinosaur Act'},
...
}
}
This way we have an object with tracks instead of a numeric array. So i can do this.props.album.tracks[2].title this instead of this.props.album.tracks.find(track => track.order == 2}).title in javascript.
``I have an use case in where this seems to be more convenient in Reactjs.
What i have tried
I thought about overriding the to_representation method. But i see that this will get me an recursive loop.
class TrackSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
print(self)
return '%s: { %s }' % (instance.order, self.to_representation(instance))
class Meta:
fields = '__all__'
model = Track
Furthermore i have searched and read the docs pretty well. But didn't find any solution for what i think should be a pretty logical solution to have out of the box. Making me think that i am wrong and missing something.
Thanks in advance.
Define a new TrackSerializer and use it in AlbumSerializer class as,
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('id', 'order', 'title')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['tracks'] = {track['id']: track for track in representation['tracks']}
return representation

Show all One2Many model field in tree view - Odoo 11.0

I have two model:
class Requisition(models.Model):
'''
This module is responsible for all of the requisition related operations.
'''
_name = 'mir.requisition'
_description = 'Mir Requisition'
name = fields.Char('Requisition Name', required=True)
company_id = fields.Many2one('res.company', string='Company')
requisition_line_ids = fields.One2many('mir.requisition.line', 'requisition_id', string='Requisition Line')
class RequisitionLine(models.Model):
'''
This module is responsible for all of the requisition line item related operations.
'''
_name = 'mir.requisition.line'
_description = 'Mir Requisition Line'
product_id = fields.Many2one(
'product.product', 'Product', required=True)
product_qty = fields.Float(
'Quantity',
digits=dp.get_precision('Product Unit of Measure'), default=0, required=True)
product_uom_id = fields.Many2one(
'product.uom', 'Unit of Measure',
oldname='product_uom', required=True)
delivery_date = fields.Date(string='Delivery Date', required=True)
delivery_location = fields.Many2one('stock.location', 'Warehouse Location', required=True)
requisition_id = fields.Many2one('mir.requisition', string='Mir Requisition Reference', index=True, ondelete='cascade')
status = fields.Selection([
('draft', 'Draft'),
('in_progress', 'In Progress'),
('approved', 'Approved'),
('cancel', 'Cancel'),
], 'draft')
#api.onchange('product_id')
def _product_onchange(self):
product = self.product_id
self.product_uom_id = self.product_id.uom_id.id
return {'domain': {'product_uom': [('category_id', '=', product.uom_id.category_id.id)]}}
and view is:
<!--Requisition Tree View-->
<record id="mir_requisition_tree" model="ir.ui.view">
<field name="name">Requisition</field>
<field name="model">mir.requisition</field>
<field name="arch" type="xml">
<tree string="Requisition">
<field name="name"/>
<field name="company_id"/>
<field name="create_uid" string="Created By"/>
<field name="create_date" string="Created Date"/>
</tree>
</field>
</record>
Currently this view showing data form parent model mir.requisition. But i want to display both model data in a single view. Any help will be appreciated.
You should take a look the invoice_form definition, it works with 'account.invoice' and 'account.invoice.line' models. Its something like this:
<!--Requisition Tree View-->
<record id="mir_requisition_tree" model="ir.ui.view">
<field name="name">Requisition</field>
<field name="model">mir.requisition</field>
<field name="arch" type="xml">
<form string="Requisition">
<field name="name"/>
<field name="company_id"/>
<field name="create_uid" string="Created By"/>
<field name="create_date" string="Created Date"/>
<field name="requisition_line_ids" nolabel="1" widget="one2many_list" >
<tree string="Requisition Lines" editable="bottom">
<!-- 'mir.requisition.line' fields -->
</tree>
</field>
</form>
</field>
</record>
I hope this answer can be helful for you.

Resources