How to use many2many in OpenERP - many-to-many

Help me to resolve this . My program is as follows I have declared many2many field in OpenERP if I choose a record to one customer it will not available to the other how its possible, The below program is mine. Help me.
from openerp.osv import orm, fields
class post_man(orm.Model):
_name = "man"
_columns = {
'name':fields.char("Name", size=50, required=True),
'description':fields.char("description", size=50),
'branch_id':fields.many2one('branches', 'Branches'),
'letter_lot':fields.many2many('letter', 'postman_letter_post', 'letter_id', 'pincode', 'Total Letters'),
# 'let_id':fields.many2one('branches','emp_id','Letter')
}
from openerp.osv import orm, fields
class post_letter(orm.Model):
_name = "letter"
_rec_name="pin"
_columns = {
"name":fields.char("Sender Name",size=50, required=True),
"address":fields.text("Destination Address"),
"pin":fields.char("Postal code",size=25),
"pincode":fields.many2one('branches','Destination'),
"postman_id":fields.one2many('man','letter_lot','PMan')
}
from openerp.osv import orm, fields
class post_man(orm.Model):
_name = "man"
_columns = {
'name':fields.char("Name", size=50, required=True),
'description':fields.char("description", size=50),
'branch_id':fields.many2one('branches', 'Branches'),
'letter_lot':fields.many2many('letter', 'postman_letter_post', 'letter_id', 'pincode', 'Total Letters'),
# 'let_id':fields.many2one('branches','emp_id','Letter')
}
from openerp.osv import orm, fields
class post_letter(orm.Model):
_name = "letter"
_rec_name="pin"
_columns = {
"name":fields.char("Sender Name",size=50, required=True),
"address":fields.text("Destination Address"),
"pin":fields.char("Postal code",size=25),
"pincode":fields.many2one('branches','Destination'),
"postman_id":fields.one2many('man','letter_lot','PMan')
}

Related

Return nested JSON from Models with relations in Django

models.py (simplified)
class Author(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
def get_books(self):
return Book.objects.filter(author=self.pk)
class Book(models.Model):
name = models.CharField(max_length=255)
pages = models.IntegerField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return f'{self.name} from {self.author}'
class Paragraph(models.Model):
name = models.CharField(max_length=255)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
def __str__(self):
return f'{self.name} from {self.book}'
I want to return all the instances in a json file with this structure:
[
{
"name": 'Dumas',
"books": {
"name": "The count of Montecristo",
"paragraphs": {
"name": "paragraph_name_1",
},
{
"name": "paragraph_name_2",
},
{
"name": "The three Musketeers",
"paragraphs": {
"name": "paragraph_name",
},
]
What I tried:
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
books = serializers.CharField(source='get_books', read_only=True)
class Meta:
model = Author
fields = ['name', 'books']
This add the books key but the value is the string representation of the istances of Book (of course), how I make the value being the serialized istances of Book? I have created a BookSerializer.
Notes:
I know that I can created a nested json by creating a serializer for Paragraph with depth = 2 but this will include fields I don't want (like pages in Book) and the json structure will be totally different.
You can create nested serializer as
class ParagraphSerializer(serializers.ModelSerializer):
class Meta:
model = Paragraph
fields = ("name",)
class BookSerializer(serializers.ModelSerializer):
paragraphs = ParagraphSerializer(source="paragraph_set", many=True, read_only=True)
class Meta:
model = Book
fields = ("name", "paragraphs")
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(source="book_set", read_only=True, many=True)
class Meta:
model = Author
fields = ['name', 'books']

How do I make my model's depdent fields appear in my JSON using Django serializers?

I'm using Django 2.0 and Python 3.7. I have the following models ...
from django.db import models
from address.models import AddressField
from phonenumber_field.modelfields import PhoneNumberField
from address.models import State
from address.models import Country
class CoopTypeManager(models.Manager):
def get_by_natural_key(self, name):
return self.get_or_create(name=name)[0]
class CoopType(models.Model):
name = models.CharField(max_length=200, null=False)
objects = CoopTypeManager()
class Meta:
unique_together = ("name",)
class Coop(models.Model):
name = models.CharField(max_length=250, null=False)
type = models.ForeignKey(CoopType, on_delete=None)
address = AddressField(on_delete=models.CASCADE)
enabled = models.BooleanField(default=True, null=False)
phone = PhoneNumberField(null=True)
email = models.EmailField(null=True)
web_site = models.TextField()
And then I created the following serializers ...
from rest_framework import serializers
from maps.models import Coop, CoopType
class CoopSerializer(serializers.ModelSerializer):
class Meta:
model = Coop
fields = ['id', 'name', 'type', 'address', 'enabled', 'phone', 'email', 'web_site']
def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Coop.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
Update and return an existing `Coop` instance, given the validated data.
"""
instance.name = validated_data.get('name', instance.name)
instance.type = validated_data.get('type', instance.type)
instance.address = validated_data.get('address', instance.address)
instance.enabled = validated_data.get('enabled', instance.enabled)
instance.phone = validated_data.get('phone', instance.phone)
instance.email = validated_data.get('email', instance.email)
instance.web_site = validated_data.get('web_site', instance.web_site)
instance.save()
return instance
class CoopTypeSerializer(serializers.ModelSerializer):
class Meta:
model = CoopType
fields = ['id', 'name']
def create(self, validated_data):
"""
Create and return a new `CoopType` instance, given the validated data.
"""
return CoopType.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
Update and return an existing `Snippet` instance, given the validated data.
"""
instance.name = validated_data.get('name', instance.name)
instance.save()
return instance
I'm trying to create an API to display my models as JSON. I created this views file
from maps.models import Coop
from maps.serializers import CoopSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class CoopList(APIView):
"""
List all coops, or create a new coop.
"""
def get(self, request, format=None):
coops = Coop.objects.all()
serializer = CoopSerializer(coops, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = CoopSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CoopDetail(APIView):
"""
Retrieve, update or delete a coop instance.
"""
def get_object(self, pk):
try:
return Coop.objects.get(pk=pk)
except Coop.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
coop = self.get_object(pk)
serializer = CoopSerializer(coop)
return Response(serializer.data)
def put(self, request, pk, format=None):
coop = self.get_object(pk)
serializer = CoopSerializer(coop, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
coop = self.get_object(pk)
coop.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
However, my dependent model, CoopType, is not getting displayed as JSON. Only its primary key is getting displayed, e.g. ...
{
"id": 915,
"name": "Young Men's Educational Network",
"type": 10,
"address": 790,
"enabled": true,
"phone": null,
"email": null,
"web_site": "www.ymenchi.com/"
},
How do I get my dependent model to appear in my JSON?
Override the to_representation(...) method of the Serializer
class CoopSerializer(serializers.ModelSerializer):
# other code snippets
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['type'] = CoopTypeSerializer(instance.type).data
return rep
Reference: DRF: Simple foreign key assignment with nested serializers?

Insert record into Db using Slick (Scala), Best practices for an Entity

First to say, I'm newcomer in Scala and really need a little help. I need to build a web api, and I'll try to insert one record into database, but have some problems with mapping the entity (db table) into a model (class). I worked with .Net Core Web API (there I used Entity Framework Core, here in Scala use Slick) and try to keep same arhitecture in Scala, but need some more informations, because on the internet I find a lot of versions, and can not choose the best.
As database, MySQL is used.
User.scala
case class User(
id: Int = 0,
userName: String,
firstName: String,
lastName: String
) {
override def equals(that: Any): Boolean = true
}
object User {
implicit object UserFormat extends Format[User] {
def writes(user: User): JsValue = {
val userSeq = Seq(
"id" -> JsNumber(user.id),
"userName" -> JsString(user.userName),
"firstName" -> JsString(user.firstName),
"lastName" -> JsString(user.lastName)
)
JsObject(userSeq)
}
def reads(json: JsValue): JsResult[User] = {
JsSuccess(User(
(json \ "id").as[Int].value,
(json \ "userName").as[String].value,
(json \ "firstName").as[String].value,
(json \ "lastName").as[String].value)
)
}
}
def tupled = (this.apply _).tupled
}
class UserMap #Inject()(protected val dbConfigProvider: DatabaseConfigProvider)(implicit ex: ExecutionContext) {
val dbConfig: DatabaseConfig[JdbcProfile] = dbConfigProvider.get[JdbcProfile]
val db: JdbcBackend#DatabaseDef = dbConfig.db
val dbUsers = TableQuery[UserDef]
def getAll(): Unit = {
val action = sql"SELECT Id, UserName, FirstName, LastName FROM Users".as[(Int, String, String, String)]
return db.run(action)
}
def add(user: User): Future[Seq[User]] = {
dbUsers += user
db.run(dbUsers.result)
}
}
UserDef.scala (which is a mapper of db table / entity)
class UserDef(tag: Tag) extends Table[User](tag, "Users") {
def id = column[Int]("Id", O.PrimaryKey, O.AutoInc)
def userName = column[String]("UserName")
def firstName = column[String]("FirstName")
def lastName = column[String]("LastName")
override def * = (id, userName, firstName, lastName) <> (create, extract)
def create(user: (Int, String, String, String)): User = User(user._1, user._2, user._3, user._4)
def extract(user: User): Option[(Int, String, String, String)] = Some((user.id, user.userName,user.firstName,user.lastName))
}
UsersController.scala
def createUser = Action(parse.json) { implicit request => {
val userJson = request.body
var user = new User(
-1,
(userJson \ "userName").as[String].value,
(userJson \ "firstName").as[String].value,
(userJson \ "lastName").as[String].value
)
var users = TableQuery[UserDef]
Await.result(db.run(DBIO.seq(
users += user,
users.result.map(println))), Duration.Inf
)
Ok(Json.toJson(user))
}
}
How I see the problem:
UserDef is an Entity and must remain clean, only table columns definitions
UserMap is the bridge between User class and UserDef (entity), can be used as a repository with crud methods (getAll(), getById(id), create(user), update(user), delete(id)). This is in same file as User class, but probably must be moved in another.
User class is the model and need to contain only their parameters and writes/reads (Scala specifics)
and now in the controller:
If I try to insert a record into database, with current method, first I need to get all rows from table, and then to add the new record in the list. What happening if I have 3 4mil records in this table? Will get all these rows useless to insert only a new row.
Then, after inserting this new row, I need to return it into client, but how I can get it updated (Id is every time -1, but if I get entire list to see what it contain, I can see the correct id for the newest entity)
thx
Finally, I found a good solution and post it here, maybe somebody need this:
UserMap, for me at least will become UserRepository. There I have CRUD operations and maybe some extra :
def getAll(): Future[Seq[User]] = {
db.run(dbUsers.result)
}
def getById(id: Int): Future[Option[User]] ={
val action = dbUsers.filter(_.id === id).result.headOption
db.run(action)
}
def create(user: User): Future[User] = {
val insertQuery = dbUsers returning dbUsers.map(_.id) into ((x, id) => x.copy(id = id))
val action = insertQuery += user
db.run(action)
}
def update(user: User) {
Try( dbUsers.filter(_.id === user.id).update(user)) match {
case Success(response) => db.run(response)
case Failure(_) => println("An error occurred!")
}
}
def delete(id: Int) {
Try( dbUsers.filter(_.id === id).delete) match {
case Success(response) => db.run(response)
case Failure(_) => println("An error occurred!")
}
}
and UsersController:
def getAll() = Action {
var users = Await.result(usersRepository.getAll(), Duration.Inf)
Ok(Json.toJson(users))
}
def getById(id: Int) = Action { implicit request => {
val user = Await.result(usersRepository.getById(id), Duration.Inf)
Ok(Json.toJson(user))
}
}
def create = Action(parse.json) { implicit request => {
val userJson = request.body
var user = new User(
-1,
(userJson \ "userName").as[String].value,
(userJson \ "firstName").as[String].value,
(userJson \ "lastName").as[String].value
)
var createdUser = Await.result(usersRepository.create((user)), Duration.Inf)
Ok(Json.toJson(createdUser))
}
}
def update(id: Int) = Action(parse.json) { implicit request => {
val userJson = request.body
var user = new User(
(userJson \ "id").as[Int].value,
(userJson \ "userName").as[String].value,
(userJson \ "firstName").as[String].value,
(userJson \ "lastName").as[String].value
)
var updatedUser = usersRepository.update(user)
Ok(Json.toJson(user))
}
}
def delete(id: Int) = Action {
usersRepository.delete(id)
Ok("true")
}
Anyway, I know I have some bad blocks of code there...especially in create & update methods, where convert json to User.
I wanted to give it a try, and here is a full working example of a Play 2.7/Scala 2.13/Slick 4.0.2 REST-API controller bound to a MySQL database.
Since you are starting with Scala, maybe it is a bit overwhelming at first to get eased with Play, Slick, etc...
So here is an humble skeleton (derived from Play-Slick GitHub)
So first, since we want to write an API, here is the conf/routes file:
GET /users controllers.UserController.list()
GET /users/:uuid controllers.UserController.get(uuid: String)
POST /users controllers.UserController.create()
PUT /users controllers.UserController.update()
DELETE /users/:uuid controllers.UserController.delete(uuid: String)
Nothing to fancy here, we just bind routes to functions in the upcoming controller.
Just notice that the 2nd GET and the DELETE expect an UUID as query param, while Json bodies with be used for the POST and PUT.
It would be nice to see the model right now, in app/models/User.scala:
package models
import java.util.UUID
import play.api.libs.json.{Json, OFormat}
case class User(
uuid: UUID,
username: String,
firstName: String,
lastName: String
) {
}
object User {
// this is because defining a companion object shadows the case class function tupled
// see: https://stackoverflow.com/questions/22367092/using-tupled-method-when-companion-object-is-in-class
def tupled = (User.apply _).tupled
// provides implicit json mapping
implicit val format: OFormat[User] = Json.format[User]
}
I used an uuid instead using a numerical id, but basically, it is the same.
Notice that a Json serializer/deserializer can be written in just one line (you don't need to detail it with case classes). I think it is also a good practice to not override it to produce Seq as found on your code, since this serializer will be very usefull when converting objects to Json on the controller.
Now the tupled definition is most likelly a hack (see comment) that will be required later on the DAO...
Next, we need a controller in app/controllers/UserController.scala:
package controllers
import java.util.UUID
import forms.UserForm
import javax.inject.Inject
import play.api.Logger
import play.api.data.Form
import play.api.i18n.I18nSupport
import play.api.libs.json.Json
import play.api.mvc._
import services.UserService
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success, Try}
class UserController #Inject()(userService: UserService)
(implicit ec: ExecutionContext) extends InjectedController with I18nSupport {
lazy val logger: Logger = Logger(getClass)
def create: Action[AnyContent] = Action.async { implicit request =>
withFormErrorHandling(UserForm.create, "create failed") { user =>
userService
.create(user)
.map(user => Created(Json.toJson(user)))
}
}
def update: Action[AnyContent] = Action.async { implicit request =>
withFormErrorHandling(UserForm.create, "update failed") { user =>
userService
.update(user)
.map(user => Ok(Json.toJson(user)))
}
}
def list: Action[AnyContent] = Action.async { implicit request =>
userService
.getAll()
.map(users => Ok(Json.toJson(users)))
}
def get(uuid: String): Action[AnyContent] = Action.async { implicit request =>
Try(UUID.fromString(uuid)) match {
case Success(uuid) =>
userService
.get(uuid)
.map(maybeUser => Ok(Json.toJson(maybeUser)))
case Failure(_) => Future.successful(BadRequest(""))
}
}
def delete(uuid: String): Action[AnyContent] = Action.async {
Try(UUID.fromString(uuid)) match {
case Success(uuid) =>
userService
.delete(uuid)
.map(_ => Ok(""))
case Failure(_) => Future.successful(BadRequest(""))
}
}
private def withFormErrorHandling[A](form: Form[A], onFailureMessage: String)
(block: A => Future[Result])
(implicit request: Request[AnyContent]): Future[Result] = {
form.bindFromRequest.fold(
errors => {
Future.successful(BadRequest(errors.errorsAsJson))
}, {
model =>
Try(block(model)) match {
case Failure(e) => {
logger.error(onFailureMessage, e)
Future.successful(InternalServerError)
}
case Success(eventualResult) => eventualResult.recover {
case e =>
logger.error(onFailureMessage, e)
InternalServerError
}
}
})
}
}
So here:
basically, each of our 5 functions referenced from the routes file check input, and then delegate the work to an injected UserService (more on that later)
for the create and update functions, you can see that we use Play Forms that I think is also a good practice. Their role is to validate the incoming Json, and that Marshall it into a User type.
Also, you can see that we use Action.async: Scala offers a very powerfull leverage with Futures so lets use it! Basically by doing so, you ensure that your code is not-blocking, thus easing the IOPS on your hardware.
Finally for the case of GET (one), GET (all), POST and PUT, since we return users, and have a deseralizer, a simple Json.toJson(user) do the work.
Before jumping to service and dao, lets see the form, in app/forms/UserForm.scala:
package forms
import java.util.UUID
import models.User
import play.api.data.Form
import play.api.data.Forms.{mapping, nonEmptyText, _}
object UserForm {
def create: Form[User] = Form(
mapping(
"uuid" -> default(uuid, UUID.randomUUID()),
"username" -> nonEmptyText,
"firstName" -> nonEmptyText,
"lastName" -> nonEmptyText,
)(User.apply)(User.unapply)
)
}
Nothing too fancy here, just as the doc says, although there is just a trick : when no uuid is defined (in the POST case, then we generate one).
Now, the service... not so much required in this very case, but in practice it might be a good thing to have an extra layer (dealing with acls for example), in app/services/UserService.scala:
package services
import java.util.UUID
import dao.UserDAO
import javax.inject.Inject
import models.User
import scala.concurrent.{ExecutionContext, Future}
class UserService #Inject()(dao: UserDAO)(implicit ex: ExecutionContext) {
def get(uuid: UUID): Future[Option[User]] = {
dao.get(uuid)
}
def getAll(): Future[Seq[User]] = {
dao.all()
}
def create(user: User): Future[User] = {
dao.insert(user)
}
def update(user: User): Future[User] = {
dao.update(user)
}
def delete(uuid: UUID): Future[Unit] = {
dao.delete(uuid)
}
}
As you can see, here, it is just a wrapper around the dao, and finnally the dao in app/dao/UserDao.scala:
package dao
import java.util.UUID
import javax.inject.Inject
import models.User
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import play.db.NamedDatabase
import slick.jdbc.JdbcProfile
import scala.concurrent.{ExecutionContext, Future}
class UserDAO #Inject()(#NamedDatabase("mydb") protected val dbConfigProvider: DatabaseConfigProvider)(implicit executionContext: ExecutionContext) extends HasDatabaseConfigProvider[JdbcProfile] {
import profile.api._
private val users = TableQuery[UserTable]
def all(): Future[Seq[User]] = db.run(users.result)
def get(uuid: UUID): Future[Option[User]] = {
db.run(users.filter(_.uuid === uuid).result.headOption)
}
def insert(user: User): Future[User] = {
db.run(users += user).map(_ => user)
}
def update(user: User): Future[User] = {
db.run(users.filter(_.uuid === user.uuid).update(user)).map(_ => user)
}
def delete(uuid: UUID): Future[Unit] = {
db.run(users.filter(_.uuid === uuid).delete).map(_ => ())
}
private class UserTable(tag: Tag) extends Table[User](tag, "users") {
def uuid = column[UUID]("uuid", O.PrimaryKey)
def username = column[String]("username")
def firstName = column[String]("firstName")
def lastName = column[String]("lastName")
def * = (uuid, username, firstName, lastName) <> (User.tupled, User.unapply)
}
}
So, here I have just adapted the code from the official play-slick example, so I guess, I do not have better comment than theirs...
Hope, the whole things helps to get a better picture :)
If something is unclear, feel free to ask!

Slick Json Column Support with MySql

I have a Json type column in MySql and I am using Scala with Slick.
How can I Provide support for the Json Column via Slick.
class SampleTable(tag: Tag) extends Table[(String, ??)](tag, "test") {
override def * : ProvenShape[NodeReference] = (name, data)
def name: Rep[String] = column[String]("name", O.PrimaryKey)
def Data: Rep[??] = column[??]("data", O.PrimaryKey)
}
Any Help will be appreciated.
Thanks In Advance
You can use a BaseColumnType to convert your JSON to a String while writing it to the database and parsing it to JSON while reading from the database:
import play.api.libs.json.{JsValue, Json}
private implicit val jsValueMappedColumnType: BaseColumnType[JsValue] =
MappedColumnType.base[JsValue, String](Json.stringify, Json.parse)
class SampleTable(tag: Tag) extends Table[(String, JsValue)](tag, "test") {
def name: Rep[String] = column[String]("name", O.PrimaryKey)
def data: Rep[JsValue] = column[JsValue]("data", O.PrimaryKey)
def * = (name, data)
}

Return only funded fields in response(Django Rest SearchFilter)

I have ViewSet which have SearchFilter in filter_backends and two search_fields. How to return JSON represents the only field results?
For example if i send response for search with "jo" substring i will have only one field for this search(funded user name or full name), not both user name and email in each JSON object:
{
[{
"username": "jonh";
},
{
"fullname": "Jonh";
},
{
"username": "jo";
},
{
"fullname": "Johnson";
}
]
}
viewsets.py:
class UserViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
queryset = User.objects.all()
permission_classes = (IsUserOrReadOnly,)
filter_backends = (filters.SearchFilter,)
search_fields = ('^username', '^fullname',)
def get_serializer_class(self):
if hasattr(self, 'action') and self.action == 'list':
return UserListSerializer
return UserDetailSerializer
serializers.py:
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'fullname')
I would create a Serializer factory function that takes the search params as an an argument:
def generate_user_list_serializer(search_terms):
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = tuple(search_terms)
return UserListSerializer
Then in your view, have the serializer generated on the fly:
def get_serializer_class(self):
# make sure that the fields are available
validated_params = [p for p in self.query_params if p in Myfields]
return generate_user_list_serializer(self.query_params)