Hello and thanks for reading this.
I am learning out to use vu.js on my own. So my knowledge so far is nearly non existent. I tried to make sense of posts that have the same issue, but I could not find my solution. First here is my problem :
I am trying to add a snippet with its tags to a database.
There are 3 tables : tags, snippets, snippet_tags
I have a function that create a snippet and it works fine when i do not use tags.
I have a function that associate tags to snippets and it works fine on its own.
Now, when i try to combine then, it does not work so I can not create a snippet with tags.
Here is my DB schema
<code>CREATE TABLE public.snippet_tags (
snippet_id integer NOT NULL,
CREATE TABLE public.snippets (
title character varying(255) NOT NULL,
description text NOT NULL,
category_id integer NOT NULL,
user_id integer NOT NULL,
created_at timestamp without time zone,
language character varying(50) NOT NULL
CREATE TABLE public.tags (
name character varying(50) NOT NULL
<code>CREATE TABLE public.snippet_tags (
snippet_id integer NOT NULL,
tag_id integer NOT NULL
);
CREATE TABLE public.snippets (
id integer NOT NULL,
title character varying(255) NOT NULL,
description text NOT NULL,
content text NOT NULL,
category_id integer NOT NULL,
subcategory_id integer,
public boolean,
user_id integer NOT NULL,
created_at timestamp without time zone,
language character varying(50) NOT NULL
);
CREATE TABLE public.tags (
id integer NOT NULL,
name character varying(50) NOT NULL
);
</code>
CREATE TABLE public.snippet_tags (
snippet_id integer NOT NULL,
tag_id integer NOT NULL
);
CREATE TABLE public.snippets (
id integer NOT NULL,
title character varying(255) NOT NULL,
description text NOT NULL,
content text NOT NULL,
category_id integer NOT NULL,
subcategory_id integer,
public boolean,
user_id integer NOT NULL,
created_at timestamp without time zone,
language character varying(50) NOT NULL
);
CREATE TABLE public.tags (
id integer NOT NULL,
name character varying(50) NOT NULL
);
Here is below the snippet_controller.py content :
from sqlalchemy.exc import SQLAlchemyError
from flask import request, jsonify
from app.models.snippet import Snippet
from app.models.tag import Tag
logger = logging.getLogger('my_logger')
data = request.get_json()
title = data.get('title')
description = data.get('description')
content = data.get('content')
category_id = data.get('category_id')
subcategory_id = data.get('subcategory_id')
public = data.get('public', False)
user_id = data.get('user_id')
language = data.get('language')
tags = data.get('tags', []) # Use tags from request body
if not all([title, description, content, category_id, user_id, language]):
logger.error("Required fields are missing")
return jsonify({"error": "All required fields must be provided"}), 400
logger.debug("Creating new snippet")
subcategory_id=subcategory_id,
db.session.add(new_snippet)
logger.debug(f"New snippet created with ID: {new_snippet.id}")
# Call associate_tags function to handle tag association
response = associate_tags(new_snippet.id, tags)
return jsonify(new_snippet.to_dict()), 201
except SQLAlchemyError as e:
logger.error(f'SQLAlchemyError: {str(e)}', exc_info=True)
return jsonify({"error": str(e.orig)}), 500
db.session.rollback() # Ensure rollback on any exception
logger.error(f'Unhandled Exception: {str(e)}', exc_info=True)
return jsonify({"error": str(e)}), 500
snippets = Snippet.query.all()
return jsonify([snippet.to_dict() for snippet in snippets])
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def get_snippet(snippet_id):
snippet = Snippet.query.get_or_404(snippet_id)
return jsonify(snippet.to_dict())
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def update_snippet(snippet_id):
data = request.get_json()
snippet = Snippet.query.get_or_404(snippet_id)
snippet.title = data.get('title', snippet.title)
snippet.description = data.get('description', snippet.description)
snippet.content = data.get('content', snippet.content)
snippet.category_id = data.get('category_id', snippet.category_id)
snippet.subcategory_id = data.get('subcategory_id', snippet.subcategory_id)
snippet.public = data.get('public', snippet.public)
snippet.language = data.get('language', snippet.language)
return jsonify(snippet.to_dict()), 200
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def delete_snippet(snippet_id):
snippet = Snippet.query.get_or_404(snippet_id)
db.session.delete(snippet)
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def associate_tags(snippet_id, tags):
snippet = Snippet.query.get_or_404(snippet_id)
snippet.tags = [] # Clear existing tags
logger.debug(f"Processing tag: {tag_name}")
tag = Tag.query.filter_by(name=tag_name).first()
logger.debug(f"Creating new tag: {tag_name}")
db.session.commit() # Commit new tag immediately
logger.debug(f"Appending tag: {tag_name} -> Tag instance: {tag}")
logger.debug("Tags associated and committed to DB")
return jsonify({"message": "Tags associated successfully"}), 200
except SQLAlchemyError as e:
logger.error(f'SQLAlchemyError: {str(e)}', exc_info=True)
return jsonify({"error": str(e.orig)}), 500
db.session.rollback() # Ensure rollback on any exception
logger.error(f'Unhandled Exception: {str(e)}', exc_info=True)
return jsonify({"error": str(e)}), 500
def get_snippets_by_tag(tag_id):
tag = Tag.query.get_or_404(tag_id)
snippets = [snippet.to_dict() for snippet in tag.snippets]
return jsonify(snippets), 200
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
<code>import logging
from sqlalchemy.exc import SQLAlchemyError
from flask import request, jsonify
from app import db
from app.models.snippet import Snippet
from app.models.tag import Tag
logger = logging.getLogger('my_logger')
def create_snippet():
data = request.get_json()
title = data.get('title')
description = data.get('description')
content = data.get('content')
category_id = data.get('category_id')
subcategory_id = data.get('subcategory_id')
public = data.get('public', False)
user_id = data.get('user_id')
language = data.get('language')
tags = data.get('tags', []) # Use tags from request body
if not all([title, description, content, category_id, user_id, language]):
logger.error("Required fields are missing")
return jsonify({"error": "All required fields must be provided"}), 400
try:
logger.debug("Creating new snippet")
new_snippet = Snippet(
title=title,
description=description,
content=content,
category_id=category_id,
subcategory_id=subcategory_id,
public=public,
user_id=user_id,
language=language
)
db.session.add(new_snippet)
db.session.commit()
logger.debug(f"New snippet created with ID: {new_snippet.id}")
# Call associate_tags function to handle tag association
response = associate_tags(new_snippet.id, tags)
if response[1] != 200:
return response
return jsonify(new_snippet.to_dict()), 201
except SQLAlchemyError as e:
db.session.rollback()
logger.error(f'SQLAlchemyError: {str(e)}', exc_info=True)
return jsonify({"error": str(e.orig)}), 500
except Exception as e:
db.session.rollback() # Ensure rollback on any exception
logger.error(f'Unhandled Exception: {str(e)}', exc_info=True)
return jsonify({"error": str(e)}), 500
def get_snippets():
try:
snippets = Snippet.query.all()
return jsonify([snippet.to_dict() for snippet in snippets])
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def get_snippet(snippet_id):
try:
snippet = Snippet.query.get_or_404(snippet_id)
return jsonify(snippet.to_dict())
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def update_snippet(snippet_id):
data = request.get_json()
try:
snippet = Snippet.query.get_or_404(snippet_id)
snippet.title = data.get('title', snippet.title)
snippet.description = data.get('description', snippet.description)
snippet.content = data.get('content', snippet.content)
snippet.category_id = data.get('category_id', snippet.category_id)
snippet.subcategory_id = data.get('subcategory_id', snippet.subcategory_id)
snippet.public = data.get('public', snippet.public)
snippet.language = data.get('language', snippet.language)
db.session.commit()
return jsonify(snippet.to_dict()), 200
except SQLAlchemyError as e:
db.session.rollback()
return jsonify({"error": str(e.orig)}), 500
def delete_snippet(snippet_id):
try:
snippet = Snippet.query.get_or_404(snippet_id)
db.session.delete(snippet)
db.session.commit()
return '', 204
except SQLAlchemyError as e:
db.session.rollback()
return jsonify({"error": str(e.orig)}), 500
def associate_tags(snippet_id, tags):
try:
snippet = Snippet.query.get_or_404(snippet_id)
snippet.tags = [] # Clear existing tags
for tag_name in tags:
logger.debug(f"Processing tag: {tag_name}")
tag = Tag.query.filter_by(name=tag_name).first()
if not tag:
logger.debug(f"Creating new tag: {tag_name}")
tag = Tag(name=tag_name)
db.session.add(tag)
db.session.commit() # Commit new tag immediately
logger.debug(f"Appending tag: {tag_name} -> Tag instance: {tag}")
snippet.tags.append(tag)
db.session.commit()
logger.debug("Tags associated and committed to DB")
return jsonify({"message": "Tags associated successfully"}), 200
except SQLAlchemyError as e:
db.session.rollback()
logger.error(f'SQLAlchemyError: {str(e)}', exc_info=True)
return jsonify({"error": str(e.orig)}), 500
except Exception as e:
db.session.rollback() # Ensure rollback on any exception
logger.error(f'Unhandled Exception: {str(e)}', exc_info=True)
return jsonify({"error": str(e)}), 500
def get_snippets_by_tag(tag_id):
try:
tag = Tag.query.get_or_404(tag_id)
snippets = [snippet.to_dict() for snippet in tag.snippets]
return jsonify(snippets), 200
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
</code>
import logging
from sqlalchemy.exc import SQLAlchemyError
from flask import request, jsonify
from app import db
from app.models.snippet import Snippet
from app.models.tag import Tag
logger = logging.getLogger('my_logger')
def create_snippet():
data = request.get_json()
title = data.get('title')
description = data.get('description')
content = data.get('content')
category_id = data.get('category_id')
subcategory_id = data.get('subcategory_id')
public = data.get('public', False)
user_id = data.get('user_id')
language = data.get('language')
tags = data.get('tags', []) # Use tags from request body
if not all([title, description, content, category_id, user_id, language]):
logger.error("Required fields are missing")
return jsonify({"error": "All required fields must be provided"}), 400
try:
logger.debug("Creating new snippet")
new_snippet = Snippet(
title=title,
description=description,
content=content,
category_id=category_id,
subcategory_id=subcategory_id,
public=public,
user_id=user_id,
language=language
)
db.session.add(new_snippet)
db.session.commit()
logger.debug(f"New snippet created with ID: {new_snippet.id}")
# Call associate_tags function to handle tag association
response = associate_tags(new_snippet.id, tags)
if response[1] != 200:
return response
return jsonify(new_snippet.to_dict()), 201
except SQLAlchemyError as e:
db.session.rollback()
logger.error(f'SQLAlchemyError: {str(e)}', exc_info=True)
return jsonify({"error": str(e.orig)}), 500
except Exception as e:
db.session.rollback() # Ensure rollback on any exception
logger.error(f'Unhandled Exception: {str(e)}', exc_info=True)
return jsonify({"error": str(e)}), 500
def get_snippets():
try:
snippets = Snippet.query.all()
return jsonify([snippet.to_dict() for snippet in snippets])
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def get_snippet(snippet_id):
try:
snippet = Snippet.query.get_or_404(snippet_id)
return jsonify(snippet.to_dict())
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
def update_snippet(snippet_id):
data = request.get_json()
try:
snippet = Snippet.query.get_or_404(snippet_id)
snippet.title = data.get('title', snippet.title)
snippet.description = data.get('description', snippet.description)
snippet.content = data.get('content', snippet.content)
snippet.category_id = data.get('category_id', snippet.category_id)
snippet.subcategory_id = data.get('subcategory_id', snippet.subcategory_id)
snippet.public = data.get('public', snippet.public)
snippet.language = data.get('language', snippet.language)
db.session.commit()
return jsonify(snippet.to_dict()), 200
except SQLAlchemyError as e:
db.session.rollback()
return jsonify({"error": str(e.orig)}), 500
def delete_snippet(snippet_id):
try:
snippet = Snippet.query.get_or_404(snippet_id)
db.session.delete(snippet)
db.session.commit()
return '', 204
except SQLAlchemyError as e:
db.session.rollback()
return jsonify({"error": str(e.orig)}), 500
def associate_tags(snippet_id, tags):
try:
snippet = Snippet.query.get_or_404(snippet_id)
snippet.tags = [] # Clear existing tags
for tag_name in tags:
logger.debug(f"Processing tag: {tag_name}")
tag = Tag.query.filter_by(name=tag_name).first()
if not tag:
logger.debug(f"Creating new tag: {tag_name}")
tag = Tag(name=tag_name)
db.session.add(tag)
db.session.commit() # Commit new tag immediately
logger.debug(f"Appending tag: {tag_name} -> Tag instance: {tag}")
snippet.tags.append(tag)
db.session.commit()
logger.debug("Tags associated and committed to DB")
return jsonify({"message": "Tags associated successfully"}), 200
except SQLAlchemyError as e:
db.session.rollback()
logger.error(f'SQLAlchemyError: {str(e)}', exc_info=True)
return jsonify({"error": str(e.orig)}), 500
except Exception as e:
db.session.rollback() # Ensure rollback on any exception
logger.error(f'Unhandled Exception: {str(e)}', exc_info=True)
return jsonify({"error": str(e)}), 500
def get_snippets_by_tag(tag_id):
try:
tag = Tag.query.get_or_404(tag_id)
snippets = [snippet.to_dict() for snippet in tag.snippets]
return jsonify(snippets), 200
except SQLAlchemyError as e:
return jsonify({"error": str(e.orig)}), 500
Then in the snippet.py you will see that :
from sqlalchemy.orm import relationship
__tablename__ = 'snippets'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255), nullable=False)
description = db.Column(db.Text, nullable=False)
content = db.Column(db.Text, nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
subcategory_id = db.Column(db.Integer, db.ForeignKey('subcategories.id'))
public = db.Column(db.Boolean, default=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
language = db.Column(db.String(50), nullable=False)
category = relationship('Category', backref=db.backref('snippets', lazy=True))
subcategory = relationship('Subcategory', backref=db.backref('snippets', lazy=True))
user = relationship('User', backref=db.backref('snippets', lazy=True))
tags = relationship('Tag', secondary='snippet_tags', back_populates='snippets')
'description': self.description,
'category_id': self.category_id,
'subcategory_id': self.subcategory_id,
'created_at': self.created_at.isoformat() if self.created_at else None,
'language': self.language,
'tags': [tag.name for tag in self.tags] # Include tag names in the dictionary
class Favorite(db.Model):
__tablename__ = 'favorites'
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
snippet_id = db.Column(db.Integer, db.ForeignKey('snippets.id'), primary_key=True)
user = relationship('User', backref=db.backref('favorites', cascade="all, delete-orphan"))
snippet = relationship('Snippet', backref=db.backref('favorites', cascade="all, delete-orphan"))
<code>from app import db
from sqlalchemy.orm import relationship
class Snippet(db.Model):
__tablename__ = 'snippets'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255), nullable=False)
description = db.Column(db.Text, nullable=False)
content = db.Column(db.Text, nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
subcategory_id = db.Column(db.Integer, db.ForeignKey('subcategories.id'))
public = db.Column(db.Boolean, default=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
language = db.Column(db.String(50), nullable=False)
# Relationships
category = relationship('Category', backref=db.backref('snippets', lazy=True))
subcategory = relationship('Subcategory', backref=db.backref('snippets', lazy=True))
user = relationship('User', backref=db.backref('snippets', lazy=True))
tags = relationship('Tag', secondary='snippet_tags', back_populates='snippets')
def to_dict(self):
return {
'id': self.id,
'title': self.title,
'description': self.description,
'content': self.content,
'category_id': self.category_id,
'subcategory_id': self.subcategory_id,
'public': self.public,
'user_id': self.user_id,
'created_at': self.created_at.isoformat() if self.created_at else None,
'language': self.language,
'tags': [tag.name for tag in self.tags] # Include tag names in the dictionary
}
class Favorite(db.Model):
__tablename__ = 'favorites'
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
snippet_id = db.Column(db.Integer, db.ForeignKey('snippets.id'), primary_key=True)
# Relationships
user = relationship('User', backref=db.backref('favorites', cascade="all, delete-orphan"))
snippet = relationship('Snippet', backref=db.backref('favorites', cascade="all, delete-orphan"))
</code>
from app import db
from sqlalchemy.orm import relationship
class Snippet(db.Model):
__tablename__ = 'snippets'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255), nullable=False)
description = db.Column(db.Text, nullable=False)
content = db.Column(db.Text, nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
subcategory_id = db.Column(db.Integer, db.ForeignKey('subcategories.id'))
public = db.Column(db.Boolean, default=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
language = db.Column(db.String(50), nullable=False)
# Relationships
category = relationship('Category', backref=db.backref('snippets', lazy=True))
subcategory = relationship('Subcategory', backref=db.backref('snippets', lazy=True))
user = relationship('User', backref=db.backref('snippets', lazy=True))
tags = relationship('Tag', secondary='snippet_tags', back_populates='snippets')
def to_dict(self):
return {
'id': self.id,
'title': self.title,
'description': self.description,
'content': self.content,
'category_id': self.category_id,
'subcategory_id': self.subcategory_id,
'public': self.public,
'user_id': self.user_id,
'created_at': self.created_at.isoformat() if self.created_at else None,
'language': self.language,
'tags': [tag.name for tag in self.tags] # Include tag names in the dictionary
}
class Favorite(db.Model):
__tablename__ = 'favorites'
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
snippet_id = db.Column(db.Integer, db.ForeignKey('snippets.id'), primary_key=True)
# Relationships
user = relationship('User', backref=db.backref('favorites', cascade="all, delete-orphan"))
snippet = relationship('Snippet', backref=db.backref('favorites', cascade="all, delete-orphan"))
Can you explain me my error and provide the correction?
The only error I see in docker is : : ‘str’ object has no attribute ‘_sa_instance_state’
Thanks for your help