one2many contains one2many how to set the value - odoo

I want to directly add the following model in onchange value
The data is from other models
My model
Class A:
_name = 'budget.budget'
main_materials_list = fields.One2many(comodel_name='budget.main.material', inverse_name='budget_id', string=u'A')
#api.onchange('suite_series')
def onchange_suite_series(self):
self.main_materials_list = self._materialValue()
def _materialValue(self):
page = []
for item in self.suite_series.main_material_ids:
product_ids = []
data = {
'product_id':self.main_materials_list.product_ids
}
for val in item.product_id:
product_item = {
'product_id': val.product_id.id
}
product_ids.append((0, 0, product_item))
data.update({'product_ids': product_ids})
page.append((0, 0, data))
return page
Class B:
_name = 'budget.main.material'
product_ids = fields.One2many(comodel_name='budget.material', inverse_name='main_id', string=u'B')
Class C:
_name = 'budget.material'
product_id = fields.Many2one(comodel_name='product.product', string=u'C')
Using the above method, then the second one2many assignment is not successful!

Related

How to save data using foreign key and retrieve full model in drf?

I am making follow-following logic in DRF Below are my codes.
Models.py
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
userId = models.UUIDField(primary_key = True,default = uuid.uuid4,editable = False,unique=True)
gender = models.CharField(max_length=1,default='M')
profilePic = models.URLField(max_length=200,default='https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png')
bio = models.TextField(null=True)
viewCount = models.IntegerField(default=0)
followers = models.IntegerField(default=0)
followings = models.IntegerField(default=0)
countryCode = models.CharField(max_length=255,default='+91')
country = models.CharField(max_length=255,default="India")
phoneNumber = models.CharField(max_length=10,default="0000000000")
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
class followAssociation(models.Model):
user = models.ForeignKey(CustomUser,related_name='user',on_delete=CASCADE)
follows = models.ForeignKey(CustomUser,related_name='follows',on_delete=CASCADE)
class Meta:
unique_together = ('user', 'follows')
Below are my serializers.
Serializers.py
from django.db.models import fields
from rest_framework import serializers
from users.models import CustomUser,followAssociation
class userSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('first_name','last_name','email','username','password','is_active','is_staff','is_superuser','bio','gender',
'viewCount','profilePic','userId','followers','followings','countryCode','country','phoneNumber')
read_only_fields = ['is_active', 'is_staff', 'is_superuser']
extra_kwargs = {'password': {'write_only': True, 'min_length': 4,'required': False},'username': {'required': False},'email': {'required': False}}
class followAssociationSerializers(serializers.ModelSerializer):
class Meta:
model = followAssociation
fields = ['user','follows']
Now my APIVIEW class
views.py
class followAssociationAPIView(APIView):
parser_classes = [JSONParser]
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request,format = None):
data = {"user":request.user.userId}
follows= get_object_or_404(CustomUser.objects.all(),userId = request.query_params["id"])
data["follows"] = follows.userId
followAssociation = followAssociationSerializers(data = data)
if followAssociation.is_valid(raise_exception=True):
followAssociation.save()
return Response(followAssociation.data,status=status.HTTP_202_ACCEPTED)
return Response(followAssociation.errors,status= status.HTTP_400_BAD_REQUEST)
def delete(self,request,format = None):
relation = get_object_or_404(followAssociation.objects.all(),follows = request.query_params["id"])
try:
data = followAssociationSerializers(relation)
relation.delete()
return Response(data.data,status=status.HTTP_200_OK)
except:
return Response(status=status.HTTP_302_FOUND)
In response, I get userId and FollowsId but I want the full user Model.
I tried depth = 1 and models.PrimaryRelatedFields() it works but only one time after I delete follow association object and next time I try to insert it says the username already exists. Please Help.
Try using Nested Serializers
You can create a new serializer class for the nested serializer and include only the fields you want. You can use the same serializer for both fields

Not null constraint failed in create method of nested serializer

I'm trying to create an apiview to add data of a nested json in the database.
The models are:
class Catch(models.Model):
haul = models.ForeignKey('hauls.Haul')
weight = models.IntegerField()
category = models.ForeignKey('species.Category')
class Sex(models.Model):
catch = models.ForeignKey('catches.Catch', related_name='sexes')
sex = models.IntegerField()
class Length(models.Model):
sex = models.ForeignKey('samples.Sex', related_name='lengths')
length = models.IntegerField()
number_individuals = models.IntegerField()
The JSON I try to store in database is:
{
"catch_id":"6125",
"sex":"2",
"lengths": [
{
"catch_id":"6125",
"length": 24,
"number_individuals": 1
},
{
"catch_id":"6125",
"length": 25,
"number_individuals": 1
},
{
"catch_id":"6125",
"length": 26,
"number_individuals": 1
}
]
}
And the serializers involved are:
class LengthSerializer(serializers.ModelSerializer):
class Meta:
model= Length
fields = ['sex_id', 'length', 'number_individuals', ]
class SexCatchSerializer (serializers.ModelSerializer):
lengths = LengthSerializer(many=True)
class Meta:
model = Sex
fields = ['id', 'sex', 'catch_id', 'lengths', ]
# This is a nested serializer, so we have to overwrite the create function
def create(self, validated_data):
# Firstly, get the data from the nested parts
lengths_data = validated_data.pop('lengths')
# Secondly, save the Sex
sex = Sex.objects.create(**validated_data)
# Then, save the nested parts in its own models
Length.objects.create(sex=sex, **lengths_data)
# And finally, return the sex
return sex
But an error django.db.utils.IntegrityError: NOT NULL constraint failed: samples_sex.catch_id is returned in sex = Sex.objects.create(**validated_data) and I can't figure out why if the catch_id field is in the JSON and obviously is not null.

Operational Error 1054 Unknown Column

class ProjectTimeAllocation(models.Model):
id = models.IntegerField(primary_key=True)
project_id = models.ForeignKey(Projects, models.DO_NOTHING, related_name='pj_id', blank=True, null=True)
project_manager_id = models.ForeignKey(ProjectManagers, models.DO_NOTHING, blank=True, null=True)
hours = models.IntegerField(blank=True, null=True)
week = models.DateTimeField(blank=True, null=True)
date_created = models.DateTimeField(auto_now=True, null=True)
last_updated = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'project_time_allocation'
views.py
def timeallocation(request, project_manager_id):
#time_list = ProjectTimeAllocation.objects.order_by('-id')
if request.method == "POST":
form = ProjectTimeAllocationForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
#post.project_manager_id = project_manager_id
post.save()
messages.success(request, "Updated Time!")
return HttpResponseRedirect('/dashboard/')
else:
form = ProjectTimeAllocationForm()
return render(request, 'dashboard/timeallocation.html', {'form':form})
forms.py
class ProjectTimeAllocationForm(forms.ModelForm):
week = forms.DateField(widget=forms.SelectDateWidget())
class Meta:
model = ProjectTimeAllocation
fields = (
'hours',
'week',
'project_manager_id',
'project_id',
)
widgets = {
}
labels = {
}
I get an operational error (1054, "Unknown column 'project_id_id' in field list. I don't understand where the extra _id is coming from? I have tried clearing the migrations and making new migrations.
It appears that django appends _id on ForeignKeys and thus I had to remove _id from my column name in the model and in the form and then django appended it back on when it generated the sql insert statement and the problem is now resolved.

Get variable dynamically

Is there any way to reference variables dynamically like methods? Here is the Groovy example of referencing a method dynamically:
class Dog {
def bark() { println "woof!" }
def sit() { println "(sitting)" }
def jump() { println "boing!" }
}
def doAction( animal, action ) {
animal."$action"() //action name is passed at invocation
}
def rex = new Dog()
doAction( rex, "bark" ) //prints 'woof!'
doAction( rex, "jump" ) //prints 'boing!'
... But doing something like this doesn't work:
class Cat {
def cat__PurrSound__List = ['a', 'b', 'c']
def cat__MeowSound__List = [1, 2, 3]
def someMethod(def sound) {
assert sound == "PurrSound"
def catSoundListStr = "cat__${obj.domainClass.name}__List"
assert catSoundListStr = "cat__PurrSound__List"
def catSoundList = "$catSoundListStr"
assert catSoundList == cat__PurrSound__List // fail
}
}
Yeah, so you can do:
def methodName = 'someMethod'
assert foo."$methodName"() == "asdf" // This works
and to get the object by name, you can do (in a Script at least):
// Cannot use `def` in a groovy-script when trying to do this
foo = new Foo()
def objectName = 'foo'
assert this."$objectName".someMethod() == "asdf"

How to use ScalaQuery to insert a BLOB field?

I used ScalaQuery and Scala.
If I have an Array[Byte] object, how do I insert it into the table?
object TestTable extends BasicTable[Test]("test") {
def id = column[Long]("mid", O.NotNull)
def extInfo = column[Blob]("mbody", O.Nullable)
def * = id ~ extInfo <> (Test, Test.unapply _)
}
case class Test(id: Long, extInfo: Blob)
Can I define the method used def extInfo = column[Array[Byte]]("mbody", O.Nullable), how to operate(UPDATE, INSERT, SELECT) with the BLOB type field?
BTW: no ScalaQuery tag
Since the BLOB field is nullable, I suggest changing its Scala type to Option[Blob], for the following definition:
object TestTable extends Table[Test]("test") {
def id = column[Long]("mid")
def extInfo = column[Option[Blob]]("mbody")
def * = id ~ extInfo <> (Test, Test.unapply _)
}
case class Test(id: Long, extInfo: Option[Blob])
You can use a raw, nullable Blob value if you prefer, but then you need to use orElse(null) on the column to actually get a null value out of it (instead of throwing an Exception):
def * = id ~ extInfo.orElse(null) <> (Test, Test.unapply _)
Now for the actual BLOB handling. Reading is straight-forward: You just get a Blob object in the result which is implemented by the JDBC driver, e.g.:
Query(TestTable) foreach { t =>
println("mid=" + t.id + ", mbody = " +
Option(t.extInfo).map { b => b.getBytes(1, b.length.toInt).mkString })
}
If you want to insert or update data, you need to create your own BLOBs. A suitable implementation for a stand-alone Blob object is provided by JDBC's RowSet feature:
import javax.sql.rowset.serial.SerialBlob
TestTable insert Test(1, null)
TestTable insert Test(2, new SerialBlob(Array[Byte](1,2,3)))
Edit: And here's a TypeMapper[Array[Byte]] for Postgres (whose BLOBs are not yet supported by ScalaQuery):
implicit object PostgresByteArrayTypeMapper extends
BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
def apply(p: BasicProfile) = this
val zero = new Array[Byte](0)
val sqlType = java.sql.Types.BLOB
override val sqlTypeName = "BYTEA"
def setValue(v: Array[Byte], p: PositionedParameters) {
p.pos += 1
p.ps.setBytes(p.pos, v)
}
def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
p.pos += 1
if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
}
def nextValue(r: PositionedResult) = {
r.pos += 1
r.rs.getBytes(r.pos)
}
def updateValue(v: Array[Byte], r: PositionedResult) {
r.pos += 1
r.rs.updateBytes(r.pos, v)
}
override def valueToSQLLiteral(value: Array[Byte]) =
throw new SQueryException("Cannot convert BYTEA to literal")
}
I just post an updated code for Scala and SQ, maybe it will save some time for somebody:
object PostgresByteArrayTypeMapper extends
BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
def apply(p: org.scalaquery.ql.basic.BasicProfile) = this
val zero = new Array[Byte](0)
val sqlType = java.sql.Types.BLOB
override val sqlTypeName = "BYTEA"
def setValue(v: Array[Byte], p: PositionedParameters) {
p.pos += 1
p.ps.setBytes(p.pos, v)
}
def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
p.pos += 1
if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
}
def nextValue(r: PositionedResult) = {
r.nextBytes()
}
def updateValue(v: Array[Byte], r: PositionedResult) {
r.updateBytes(v)
}
override def valueToSQLLiteral(value: Array[Byte]) =
throw new org.scalaquery.SQueryException("Cannot convert BYTEA to literal")
}
and then usage, for example:
...
// defining a column
def content = column[Array[Byte]]("page_Content")(PostgresByteArrayTypeMapper)