sql_cosntraints on exitsing field from original module - odoo-8

In product.template there is field default_code. Is it' possible to add sql_constraints that default code should be unique. Because this code doesn't work. Or do i need override default_code field in my costume module?
class ProductProduct(models.Model):
_inherit = 'product.template'
_sql_constraints = [
('code_uniq', 'unique (default_code)', "Default code already exists!"),
]

Please try with Python constrain may its useful for you :
import this lines in python file :
from openerp.exceptions import ValidationError
Any write this method in your class :
#api.constrains('default_code')
def _check_default_code(self):
code = self.search([('default_code','=',self.default_code)])
if len(code) > 1:
raise ValidationError(_("Duplicate Record"))

I would add the constraint on model product.product because that's where this information (product reference) really is used. But default_code on product.template will only work since Odoo V10. In Odoo V8 and V9 it was a unstored related field, so not in DB. So you have to add the constraint on model product.product.
class ProductProduct(models.Model):
_inherit = 'product.product'
_sql_constraints = [
('code_uniq', 'unique(default_code)', "Default code already exists!"),
]
Important to know: If the module, which sets up the constraint, is updated while the constraint will fail (e. g. the default_code actually twice in db), it won't create a sql constraint in db. So you have to clean up the data and update the module again or create the constraint in the db by yourself.

Related

Django REST Framework - access verbose_name of fields in ModelSerializer

Say I have the following Model:
class Book(Model):
title = CharField(verbose_name="Book title")
and a ModelSerializer:
class BookSerializer(ModelSerializer):
class Meta:
model = Book
fields = "__all__"
I would like to have a function get_verbose_names which returns verbose names of the fields in the model. This is what I have so far:
def get_verbose_names(serializer):
return [field.label for field in serializer.get_fields().values()]
It seems to work fine but problems occur when I use this for the builtin User model. The only fields which work are ID, E-mail, Active, Superuser status and Staff status. The special thing about those fields is that their verbose name differs from their name. Django REST Framework is probably hiding a super-smart logic which checks this and refuses to set the field label to its verbose name in such cases.
Do Django REST Framework's fields have the verbose names hidden somewhere, or they don't copy them from the original Django model fields at all and I am screwed? Or will the trick be to override this logic? I tried and could not find it.
Django REST Framework really has the mentioned "super-smart logic". It is the function needs_label in utils.field_mapping:
def needs_label(model_field, field_name):
"""
Returns `True` if the label based on the model's verbose name
is not equal to the default label it would have based on it's field name.
"""
default_label = field_name.replace('_', ' ').capitalize()
return capfirst(model_field.verbose_name) != default_label
Probably the easiest way to bypass this annoying feature is to do this:
def get_verbose_names(serializer):
return [field.label or name.replace("_", " ").capitalize()
for name, field in serializer.get_fields().items()]
Explained in words, check the field label and if none was auto-generated for it, use the needs_label logic to determine it.

How to create products attributes like the one in django-shop

I liked the way how django-shop is creating new products attributes by developping a product model. Ex: SmartPhone... I would like to add products attributes the same way but I do not know by where to start. By experience, when I am copying code from an app, I end up deleting the app as it doesn't work correctly.
My product model is:
`class Product(models.Model):
name = models.CharField('name', max_length=32)
slug = models.SlugField('slug', max_length=32)
description = models.TextField('description')
class Meta:
ordering = ['name']`
It would be great if you could advice me on how to add similar products attributes. This way I could create attributes like this example. I don't want to copy all the app because there is a lot of things that I don't need. [Smartcard example][1]https://github.com/awesto/django-shop/tree/master/example/myshop/models
First of all, you have to decide, whether you need a polymorphic approach or not. I assume your products do not vary that much, hence you don't need polymorphism.
Therefore something such as the smartcard example should be enough:
from shop.money.fields import MoneyField
from shop.models.product import BaseProduct, BaseProductManager, CMSPageReferenceMixin
from shop.models.defaults.mapping import ProductPage, ProductImage
class Product(CMSPageReferenceMixin, BaseProduct):
# common product fields
product_name = models.CharField(max_length=32)
slug = models.SlugField()
unit_price = MoneyField(decimal_places=3)
description = models.TextField("Description")
objects = BaseProductManager()

Odoo 9.0C: How can i access the value of a many2one field (that has been created in sale.order.line module on the invoice qweb report?

I have installed module Sale Sourced by Line
by Camptocamp, Eficent, SerpentCS, Odoo Community Association (OCA) for Odoo 9.0.
The module creates a new many2one field as the code bellow:
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
warehouse_id = fields.Many2one(
'stock.warehouse',
'Source Warehouse',
readonly=True,
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
help="If a source warehouse is selected, "
"it will be used to define the route. "
"Otherwise, it will get the warehouse of "
"the sale order")
Now i would like to access the value warehouse_id on account_invoice_report qweb. Please tell me what are posible solutions for my purpose? Thank for your time,
In account.invoice.line one field available sale_line_ids, based on that you can search warehouse_id from sale.order.line.
invoice.invoice_line_ids.mapped('sale_line_ids').mapped('warehouse_id')
This may help you.

Dealing with unique constraints that should be replaced in django_rest_framework

tl;dr: How can I ignore (turn off) a unique constraint in django_rest_framework Create calls with a ListCreateAPIView, because I'm going to deal with it manually in the perform_create method?
Im using a third party library django-push-notifications. It has a nice model for APNSDevice (apple push notification service device) that has a unique constraint on a registration_id field.
My problem is that sometimes I want to manually delete old values in the table that have the registration ID, so that I can insert a new value. I'd like to use this serializer:
class APNSDeviceSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = APNSDevice
fields = ('name', 'active', 'device_id', 'registration_id')
along with this code for PUT
class MyAppleDevices(generics.ListCreateAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = APNSDeviceSerializer
model = APNSDevice
def get_queryset(self):
return APNSDevice.objects.filter(user = self.request.user)
def perform_create(self, serializer):
print "Looking for old devices with registration id "+str(self.request.registration_id)
oldDevices = APNSDevice.objects.filter(registration_id = self.request.registration_id)
for oldDevice in oldDevices:
oldDevice.delete()
apnsDevice = serializer.save(user=self.request.user)
In other words, I'm trying to manually delete other entries that have the unique constraint in this particular PUT, so that I can insert the new one without violating the unique constraint. The problem is the validator runs before the perform_create method is called, and I can't figure out how to turn off the validator's unique constraint. I tried adding this to the Serializer
def get_validation_exclusions(self, instance = None):
exclusions = super(APNSDeviceSerializer, self).get_validation_exclusions(instance)
return exclusions + ['registration_id']
but it doesn't help so obviously I have no clue even though I've been pouring through the documentation and Stack Overflow posts. Any help appreciated, thanks. I suppose as a last resort I could remove the unique constraint from the model, but it is a valid constraint so I'd rather leave it in.
I found this question because I had this exact problem with that exact library. You can get around it by subclassing the serializer and manually overriding the field definition:
class APNSDeviceSerializerWithNonUniqueRegistrationId(APNSDeviceSerializer):
registration_id = serializers.CharField(min_length=64, max_length=64)
class Meta(APNSDeviceSerializer.Meta):
fields = ("name", "registration_id", "device_id", "active", "date_created")
Then, if you're using django-push-notifications, you'll also need to override the ViewSet that uses that serializer:
class APNSDeviceAuthorizedViewSetWithNonUniqueRegistrationId(AuthorizedMixin, APNSDeviceViewSet):
"""
The out of the box viewset/serializer combo require the registration ID to be unique and won't
allow setting a registration ID to a new user (which is useful if we have potentially more than
one account on a device.)
"""
serializer_class = APNSDeviceSerializerWithNonUniqueRegistrationId
def perform_create(self, serializer):
if self.request.user.is_authenticated():
try:
existing_registration = APNSDevice.objects.get(
registration_id=serializer.validated_data['registration_id'])
existing_registration.delete()
except APNSDevice.DoesNotExist:
pass
serializer.save(user=self.request.user)
return super(DeviceViewSetMixin, self).perform_create(serializer)

django - how to check in a clean method of a form whether it is an insert or an update

I have a form where I validate in the clean method whether a ProjectMembership object already exist, that has the same values for project and member. This is due that I have in the ProjectMembership model defined a unique_together constraint for project and member. This works fine actually.
class ProjectMembershipForm(forms.ModelForm):
project = forms.ModelChoiceField(Project.objects, widget=HiddenInput())
class Meta:
model = ProjectMembership
def clean(self):
cleaned_data = self.cleaned_data
project = cleaned_data.get("project")
member = cleaned_data.get("member")
print ProjectMembership.objects.filter(project=project, member=member).count()
if ProjectMembership.objects.filter(project=project, member=member).count() > 0:
del cleaned_data["project"]
del cleaned_data["member"]
raise forms.ValidationError('The user "%s" is already part of the project team for project "%s".' % (member, project))
return cleaned_data
But now I'm asking myself how I can judge in the clean method whether the user tries to create a new relationship or update a relationship. Because with this clean method it is not possible to do an update, since it returns the error message that the entry already exist.
Try this:
if self.instance.pk:
update_procedure()
else:
insert_procedure()
You can try changing this:
if ProjectMembership.objects.filter(project=project, member=member).count() > 0:
to something like this:
if ProjectMembership.objects.filter(project=project, member=member).exclude(pk=self.instance.id).count() > 0:
actually you need to check if self.instance is not None before you use it in exclude but hopefully this little snippet gave you some idea how yo can accomplish your task without having forms duplicated.

Resources