how to perform join query with sql alchemy with postgres - postgresql

ExpenseList table have two foreign keys, i want to fetch list of expenses from this category with corresponding category. Currently it is returning category_id only when i am applying following query:
query = ExpenseList.query.filter_by(user_id=6)
return make_response(jsonify([i.serialize for i in query.all()])),200
Its returning response like this:
[
{
"category": 3,
"created_on": "Sun, 05 Nov 2017 09:40:19 GMT",
"money_spent": "50",
"name": "DVD"
},
{
"category": 3,
"created_on": "Sun, 05 Nov 2017 09:40:39 GMT",
"money_spent": "100",
"name": "Movie"
}
]
Model schema is
class ExpenseList(db.Model):
__tablename__ = 'expense_list'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(500), unique=True, nullable=False)
money_spent = db.Column(db.String(500), nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('category_list.id'))
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
is_recurring = db.Column(db.Boolean,nullable=False, default=False)
created_on = db.Column(db.DateTime, nullable=False)
#property
def serialize(self):
return {
'name' : self.name,
'money_spent' : self.money_spent,
'category' : self.category_id,
'created_on' : self.created_on
}
class CategoryList(db.Model):
__tablename__ = 'category_list'
id = db.Column(db.Integer,primary_key = True, autoincrement=True)
name = db.Column(db.String(500), unique=True, autoincrement=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
created_on = db.Column(db.DateTime, nullable=False)
How can i get category name instead of category_id in response object, I also tried backrefs, lazy etc but don't know where i am going wrong.

Here is a join You want
query(ExpenseList.name.label('expense_name'),
ExpenseList.money_spent,
CategoryList.name.label('category_name'),
ExpenseList.created_on)\
.join(CategoryList, ExpenseList.category_id == CategoryList.id)\
.filter_by(ExpenseList.user_id=6)
and a worrying part in Your CategoryList model is:
name = db.Column(db.String(500), unique=True, autoincrement=True)

Related

Nested one-to-many relations in flask-admin

I have such models in my project:
class Ingredient(Base):
__tablename__ = 'ingredient'
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
measurement_unit = Column(String)
ingredient_amount = relationship('IngredientAmount', back_populates='ingredient')
def __str__(self):
return self.name
class IngredientAmount(Base):
__tablename__ = 'ingredient_amount'
id = Column(Integer, primary_key=True, index=True, nullable=True)
ingredient_id = Column(Integer, ForeignKey('ingredient.id'))
recipe_id = Column(Integer, ForeignKey('recipe.id'))
amount = Column(Integer)
ingredient = relationship('Ingredient', back_populates='ingredient_amount')
recipes = relationship(
'Recipe',
back_populates='ingredients',
cascade='all, delete'
)
class Recipe(Base):
__tablename__ = 'recipe'
id = Column(Integer, primary_key=True, index=True)
text = Column(String)
name = Column(String, unique=True)
author_id = Column(Integer, ForeignKey('user.id'))
ingredients = relationship(
'IngredientAmount',
back_populates='recipes',
cascade='all, delete'
)
So when I look at recipe in flask-admin i'd like to see ingredients which loads IngredientAmount instance and IngredientAmount instance loads Ingredient instance. I tried to implement view as:
class RecipeView(ModelView):
can_edit = True
can_create = True
can_delete = True
can_view_details = True
column_auto_select_related = True
column_display_pk = True
column_display_all_relations = True
column_display_actions = True
def get_query(self):
return self.session.query(Recipe).order_by(Recipe.id).options(
joinedload(Recipe.ingredients).joinedload(IngredientAmount.ingredient)
).options(joinedload(Recipe.tags)).options(
joinedload(Recipe.author)
)
But I see <models.IngredientAmount object at 0x7f6e7b7edd80>. Is it possible to do what I want?

Flask SQLAlchemy, IntegrityError, ForeignKeyViolation - Creating relationships between tables

I'm trying to create a Flask app where I can return a list of 'workspaces' from a postgresql database, a list of 'categories and a list of 'projects'.
In projects.py, when a GET method is called, the database will return all of the 'workspaces' and all of the 'categories' and get both the id and name for each, I can then put this in a dropdown button for the user to select. This part of the code works fine.
When a POST method is called, this should add a new row to the 'projects' table to define a new project, along with this should be the workspace_id and the categories_id that the user selected.
This part of the code is not working, I get the following error message:
sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "projects" violates foreign key constraint "workspace_id"
DETAIL: Key (id)=(19) is not present in table "workspaces".
[SQL: INSERT INTO projects (name, description, category_id, workspace_id, visibility_level, slug) VALUES (%(name)s, %(description)s, %(category_id)s, %(workspace_id)s, %(visibility_level)s, %(slug)s) RETURNING projects.id]
[parameters: {'name': 'Brand New Project', 'description': 'gfhfghfg', 'category_id': '1', 'workspace_id': '1', 'visibility_level': '1', 'slug': 'brand-new-project'}]
models.py:
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from taskmanagement.database import Base
class Projects(Base):
__tablename__ = 'projects'
id = Column(Integer, primary_key=True)
name = Column(String(140), unique=True)
description = Column(String(140), unique=True)
category_id = Column(Integer, ForeignKey('categories.id'), unique=False, nullable=False)
category = relationship('Categories', lazy=True, uselist=False, primaryjoin="Categories.id == Projects.category_id")
workspace_id = Column(Integer, ForeignKey('workspaces.id'), unique=False, nullable=False)
workspace = relationship('Workspaces', lazy=True, uselist=False, primaryjoin="Projects.workspace_id == Workspaces.id")
visibility_level = Column(Integer, unique=False)
slug = Column(String(240), unique=True)
def __init__(self, name=None, description=None, category_id=None, workspace_id=None, visibility_level=None, slug=None):
self.name = name
self.description = description
self.category_id = category_id
self.workspace_id = workspace_id
self.visibility_level = visibility_level
self.slug = slug
def __repr__(self):
return f'<Projects {self.name!r}>'
class Workspaces(Base):
__tablename__ = 'workspaces'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
def __init__(self, name=None):
self.name = name
def __repr__(self):
return f'<Workspaces {self.name!r}>'
class Categories(Base):
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
def __init__(self, name=None):
self.name = name
def __repr__(self):
return f'<Workspaces {self.name!r}>'
Projects.py
#projects.route('/projects/add', methods = ['POST', 'GET'])
def project_add():
if request.method == 'GET':
categories = Categories.query.all()
workspaces = Workspaces.query.all()
categories_results = [
{
"id": category.id,
"name": category.name
} for category in categories]
workspaces_results = [
{
"id": workspace.id,
"name": workspace.name
} for workspace in workspaces]
results = {"categories": categories_results, "workspaces": workspaces_results}
return render_template('project_add.html', title='Add Project', results=results)
else:
name = request.form['project_name']
slug = request.form['project_slug']
description = request.form['project_desc']
visibility_level = request.form['project_visibility']
category_id = request.form['category_id']
workspace_id = request.form['workspace_id']
form_results = {
"name": request.form['project_name'],
"slug": request.form['project_slug'],
"description": request.form['project_desc'],
"visibility_level": request.form['project_visibility'],
"category_id": request.form['category_id'],
"workspace_id": int(request.form['workspace_id'])
}
#return form_results
results = Projects(name, description, category_id, workspace_id, visibility_level, slug)
db_session.add(results)
db_session.commit()
I'm completely stuck of this problem. Can anyone tell me what I'm doing wrong?

Return Django ORM union result in Django-Graphene

I am trying to query two separate objects and return them as a single result set. I've tried using a Union and an Interface, but not sure what I'm doing wrong there.
My model:
class BaseActivity(models.Model):
class Meta:
abstract = True
name = models.CharField(db_column="activity_type_name", unique=True, max_length=250)
created_at = CreationDateTimeField()
modified_at = ModificationDateTimeField()
created_by = models.UUIDField()
modified_by = models.UUIDField()
deleted_at = models.DateTimeField(blank=True, null=True)
deleted_by = models.UUIDField(blank=True, null=True)
class Activity(BaseActivity):
class Meta:
db_table = "activity_type"
ordering = ("sort_order",)
id = models.UUIDField(
db_column="activity_type_id",
primary_key=True,
default=uuid.uuid4,
editable=False,
)
sort_order = models.IntegerField()
def __str__(self):
return self.name
class CustomActivity(BaseActivity):
class Meta:
db_table = "organization_custom_activity_type"
id = models.UUIDField(
db_column="organization_custom_activity_type",
primary_key=True,
default=uuid.uuid4,
editable=False,
)
farm = models.ForeignKey("farm.Farm", db_column="organization_id", on_delete=models.DO_NOTHING, related_name="custom_activity_farm")
My schema:
class FarmActivities(graphene.ObjectType):
id = graphene.String()
name = graphene.String()
class ActivityType(DjangoObjectType):
class Meta:
model = Activity
fields = ("id", "name", "requires_crop", "sort_order")
class CustomActivityType(DjangoObjectType):
class Meta:
model = CustomActivity
fields = ("id", "name", "farm")
And the query:
class Query(graphene.ObjectType):
get_farm_activities = graphene.Field(FarmActivities, farm=graphene.String(required=True))
def resolve_get_farm_activities(self, info, farm):
farm_activities = Activity.objects.values("id", "name").filter(
farmtypeactivityrel__farm_type__farm=farm, deleted_at=None
)
custom_activities = CustomActivity.objects.values("id", "name").filter(farm=farm, deleted_at=None)
return list(chain(farm_activities, custom_activities))
With this, I do get a list back from the query, but it's not going thru the resolver when I call getFarmActivities.
Literally the list returns:
ExecutionResult(data={'getFarmActivities': {'id': None, 'name': None}}, errors=None)
How to resolve graphene.Union Type?
That provided the hint I needed to get this working. I had to build a Union that would parse the model and not the schema type.
class FarmActivities(graphene.Union):
class Meta:
types = (ActivityType, CustomActivityType)
#classmethod
def resolve_type(cls, instance, info):
if isinstance(instance, Activity):
return ActivityType
if isinstance(instance, CustomActivity):
return CustomActivityType
return FarmActivities.resolve_type(instance, info)
Which then allowed me to run the query like so:
def resolve_get_farm_activities(self, info, farm):
farm_activities = Activity.objects.filter(
farmtypeactivityrel__farm_type__farm=farm
)
custom_activities = CustomActivity.objects.filter(farm=farm)
return list(chain(farm_activities, custom_activities))
And the API query:
query farmParam($farm: String!)
{
getFarmActivities(farm: $farm)
{
... on CustomActivityType
{
id
name
}
... on ActivityType
{
id
name
}
}
}

Why are default values for PostgreSQL on insert not working?

I have a PostgreSQL database on Heroku and I've connected to that using PopSQL. Here is the model for the table (using Flask + SQLAlchemy) -
class User(db.Model):
__tablename__ = 'users'
email = Column(String, primary_key=True)
group = Column(String)
age = Column(String)
gender = Column(String)
category = Column(String)
isEnrolled = Column(Boolean)
logCount = Column(Integer, default=0)
logged = Column(ARRAY(Boolean), default=[None]*14)
medMin = Column(ARRAY(Integer), default=[None]*14)
def __init__(self, email, age, group ,gender, category):
self.email = email
self.age = age
self.group = group
self.gender = gender
self.category = category
The table was created using db.create_all()
In PopSQL, when I do an INSERT of the form:
INSERT INTO users(email,"group",age,gender,category)
VALUES('abc#gmail.com','other','20-30','Female','intrinsic');
The columns of logCount, logged and medMin are set to null and not their default values. Why is this happening?

entity Framework Seeding related data

I'm trying to figure out how to seed one to many data elements in the seed method of Entity Framework.
context.AddressTypes.AddOrUpdate(
p => p.Name,
new AddressType { Name = "Original" },
new AddressType { Name = "Shipping" },
new AddressType { Name = "Billing" }
);
context.Addresses.AddOrUpdate(
a => a.Address1,
new Address { Address1 = "123 West Main",
City = "Hannibal",
Region = "MO",
PostalCode = "12345",
Country = "USA",
Type = new AddressType { Id=1 } }
);
How do I add one of the three address types to the address object I am seeding? If I do it the way I have shown it creates a new object in the AddressTypes table.