I am trying to paginate a secondary table for Client but it doesn't work, the results always more than the per_page parameter that by default shows only three items per page .
Here is my models.py:
subscribers = db.Table(
'clients_subscribed',
db.Column('client_id', db.Integer, db.ForeignKey('client.id', ondelete='CASCADE')),
db.Column('user_id', db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'))
)
class Client(db.Model, UserMixin):
id = db.Column(db.Integer(), primary_key=True)
public_id = db.Column(db.String(50), default=uuid.uuid4)
name = db.Column(db.String())
subscribed_users = db.relationship(
'User',
secondary=subscribers,
backref=db.backref('user', passive_deletes=True, lazy='dynamic')
)
Here is also my views.py :
from flask import current_app
current_app.config['SUBSCRIBERS_PER_PAGE'] = 3
#api_route.route('/client/subscribers/<string:category>/<string:client_id>', methods=['GET'])
#token_required
def subscribers(current_user, category, client_id):
if request.method == 'GET':
page = request.args.get('page', 1, type=int)
client = Client.query.filter_by(public_id=client_id).first()
if not client:
raise InvalidUsage(u'404, not found!', status_code=404)
pagination = # Paginate Client.subscribed_users
psubscribers = pagination.items
subscribers = {}
prev = None
if pagination.has_prev:
prev = url_for('api.subscribers', category=category, client_id=client_id, page=page-1, _external=True)
next = None
if pagination.has_next:
next = url_for('api.subscribers', category=category, client_id=client_id, page=page+1, _external=True)
for client in client.subscribed_users:
subscribers_case = {
'id': client.id,
'public_id': client.public_id,
'image': '/static/img/'+client.image if client.image else '/static/img/logo.png',
'name': client.name,
}
subscribers[client.public_id] = subscribers_case
return jsonify({
'subscribers' : subscribers,
'prev' : prev,
'next': next,
'count' : pagination.total
})
return jsonify({'error' : 'No data!'})
Also here is the class User in models:
class User(db.Model, UserMixin):
__tablename__ = 'user'
id = db.Column(db.Integer(), primary_key=True)
public_id = db.Column(db.String(50), default=uuid.uuid4)
name = db.Column(db.String())
family = db.Column(db.String())
bio = db.Column(db.String())
tele = db.Column(db.String(), unique=True)
password = db.Column(db.String())
clients = db.relationship('Client', backref='user', passive_deletes=True, lazy='dynamic')
news = db.relationship('News', backref='user', passive_deletes=True, lazy='dynamic')
notifications = db.relationship('Notification', backref='user', passive_deletes=True, lazy='dynamic')
image = db.Column(db.String(), nullable=True)
slug = db.Column(db.String())
roles = db.relationship(
'Role',
secondary=roles,
backref=db.backref('users', lazy='joined',
passive_deletes=True,
single_parent=True)
)
subscribed_clients = db.relationship(
'Client',
secondary=subscribers,
backref=db.backref('client', passive_deletes=True, lazy='joined')
)
Any suggestions guys how to make that work !!!
You need to use lazy=dynamic in the relationship in order to get a Query object back. Documentation here, and another StackOverflow question about this here.
Related
Building a Flask application i am getting this error
AttributeError: 'str' object has no attribute '_sa_instance_state'
when trying to pass a value selected by user from SelectField from Forms
class UpdateAccountForm(FlaskForm):
name = StringField('Name', validators=[DataRequired(), Length(min=2, max=50)])
surname = StringField('Surname', validators=[Length(min=2, max=80)])
email = StringField('Email', validators=[DataRequired(), Email()])
picture = FileField('Update Profile Picture', validators=[FileAllowed(['jpg', 'svg'])])
province = SelectField(u'Select Province', choices=[('Choose', '--') ,('EC', 'Eastern Cape'), ('FS', 'Free State'), ('GP', 'Gauteng')])
#province = SelectField(u'Select Province', choices=PROVINCES, coerce=str)
submit = SubmitField('Update')
and model
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement = True)
name = db.Column(db.String(50))
surname = db.Column(db.String(80))
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.svg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
#province = db.Column(db.String(180))
province = db.relationship('Moter', backref='user', uselist=False)
class Moter(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement = True)
short_intro = db.Column(db.Text(100))
about_me = db.Column(db.Text(260))
date_joined = db.Column(db.DateTime(timezone=True), default=func.now())
province = db.Column(db.String(180), nullable=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
and my route
#app.route('/update_profile', methods=['GET', 'POST'])
#login_required
def update_profile():
form = UpdateAccountForm()
if form.validate_on_submit():
if form.picture.data:
picture_file = save_picture(form.picture.data)
current_user.image_file = picture_file
current_user.email = form.email.data
current_user.name = form.name.data
current_user.surname = form.surname.data
current_user.province = form.province.data #dict(PROVINCES).get(form.province.data)
db.session.commit()
flash('Your account has been updated', 'success')
return redirect(url_for('profile'))
elif request.method == 'GET':
form.name.data = current_user.name
form.surname.data = current_user.surname
form.email.data = current_user.email
image_file = url_for('static', filename='profile_pics/' + current_user.image_file)
return render_template('update_profile.html', title='Update Profile', image_file=image_file, form=form)
Could someone shed some light what i am doing wrong - i looked at other posts relating to this but i don't quite get how to update my SelectField to pass relevant data
from datetime import datetime
from pack import db,login_manager
from flask_login import UserMixin
# SQLALCHEMY_TRACK_MODIFICATIONS = False
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique = True, nullable = False)
email = db.Column(db.String(150), unique = True, nullable = False)
password = db.Column(db.String(60), nullable = False)
profile_pic = db.Column(db.String(20), nullable = False, default = "default_profile_pic.jpg")
posts = db.relationship('Post', backref = 'author', lazy = True)
comments = db.relationship('Comment', backref = 'commentor', lazy = True)
def __repr__(self):
return f"User('{self.username}','{self.email}','{self.profile_pic}')"
class Post(db.Model,UserMixin):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable = False)
date_posted = db.Column(db.DateTime, nullable = False, default = datetime.utcnow)
content = db.Column(db.Text, nullable = False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable = False)
post_comments = db.relationship('Comment', backref = 'commentor', lazy = 'dynamic')
def __repr__(self):
return f"Post('{self.title}','{self.content}','{self.date_posted}','{self.comments}')"
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
comment = db.Column(db.String(100000), nullable = False)
timestamp = db.Column(db.DateTime, nullable = False, default = datetime.utcnow, index = True)
user_comment_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable = False)
post_comment_id = db.Column(db.Integer, db.ForeignKey('post.id'))
def __repr__(self):
return f"Post('{self.comment}','{self.user_comment_id}','{self.post_comment_id}')"
This give this error:
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class Post->post'. Original exception was: Error creating backref 'commentor' on relationship 'Post.post_comments': property of that name exists on mapper 'mapped class Comment->comment'
Please help me resolve this error. I want to add a feature to comment on a post and for that i am trying to connect the Comment model with Post and User models.
In your error you have: Post.post_comments': property of that name exists on mapper 'mapped class Comment->comment.
It seems that in User you have comments which creates a backref 'commentor' in Comment and in Post you have post_comments which also creates a backref 'commentor' in Comment.
For example in Post, you can change post_comment to :
post_comments = db.relationship('Comment', backref = 'post_commented', lazy = 'dynamic')
Edit:
When defining a One to Many relationship with backref parameter, there is no need of user_id (in Post), user_comment_id (in Comment), post_comment_id (in Comment): Simply remove them.
You should have another look at https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html#one-to-many (the backref part)
I have been trying to make a relationship between two table and have a QuerySelectFiled to select a field from the other table, I have managed to do so, but the problem came when I wanted to submit the field I keep getting :
InterfaceError: <unprintable InterfaceError object>
after debugging the issue I found out that when the form is submitted the value of the field is being submitted not the id, I have solved that by saying in my model
self.firstAuthor = firstAuthor.id
solved the issue but if I choose the empty value it will break because the empty field does not have property id.
so can someone suggest how to do that?
here is my form:
from wtforms_alchemy import QuerySelectField, QuerySelectMultipleField
from ....module1.authors.author.authorModel import Author
from flask_wtf import FlaskForm
from wtforms import SubmitField, HiddenField, BooleanField, SelectField, StringField, FileField, IntegerField, DateTimeField
from datetime import datetime
from wtforms.validators import DataRequired
def getAuthor():
return Author.query
class PublicationsForm(FlaskForm):
id = HiddenField()
title = StringField('Title', validators=[DataRequired()])
category = SelectField('Category', choices=[('', ''),('Journal', 'Journal'), ('Conference', 'Conference'), ('Talk', 'Talk'),('Talk2', 'Talk2'),('Talk3', 'Talk3')])
year = DateTimeField('Year', format='%Y')
publisher = BooleanField('Publisher')
volume = IntegerField('Volume')
issue = IntegerField('Issue')
pages = StringField('Pages')
location = StringField('Location')
note = StringField('Note')
fullCitation = FileField('FullCitation')
fullSource = FileField('FullSource')
finalVersion = FileField('FinalVersion')
firstAuthor = QuerySelectField("FirstAuthor", query_factory=getAuthor, get_label="lastName", allow_blank=True, blank_text='')
secondAuthor = QuerySelectField("SecondAuthor", query_factory=getAuthor, get_label="lastName", allow_blank=True, blank_text='')
thirdAuthor = QuerySelectField("ThirdAuthor", query_factory=getAuthor, get_label="lastName", allow_blank=True, blank_text='')
fourthAuthor = QuerySelectField("FourthAuthor", query_factory=getAuthor, get_label="lastName", allow_blank=True, blank_text='')
fifthAuthor = QuerySelectField("FifthAuthor", query_factory=getAuthor, get_label="lastName", allow_blank=True, blank_text='')
sixthAuthor = QuerySelectField("SixthAuthor", query_factory=getAuthor, get_label="lastName", allow_blank=True, blank_text='')
submit = SubmitField("Save")
here is my model:
from sqlalchemy import Column, Integer, String, Boolean, DateTime
from app import db
class Publications(db.Model):
id = db.Column(Integer, primary_key=True)
title = db.Column(String, nullable=False)
category = db.Column(String, nullable=False)
year = db.Column(db.DateTime)
publisher = db.Column(Boolean)
volume = db.Column(Integer)
issue = db.Column(String)
pages = db.Column(String)
location = db.Column(String)
note = db.Column(String)
fullCitation = db.Column(String)
fullSource = db.Column(String)
finalVersion = db.Column(String)
issue = db.Column(db.Text)
firstAuthor = db.Column(db.Integer, db.ForeignKey('author.id'))
secondAuthor = db.Column(db.Integer, db.ForeignKey("author.id"),nullable=True )
thirdAuthor = db.Column(db.Integer, db.ForeignKey("author.id"),nullable=True )
fourthAuthor = db.Column(db.Integer, db.ForeignKey("author.id"),nullable=True )
fifthAuthor = db.Column(db.Integer, db.ForeignKey("author.id"),nullable=True )
sixthAuthor = db.Column(db.Integer, db.ForeignKey("author.id"),nullable=True )
def __init__(self, title, category, year, publisher, volume, issue, pages, location, note, fullCitation, fullSource, finalVersion, firstAuthor, secondAuthor, thirdAuthor, fourthAuthor, fifthAuthor, sixthAuthor):
self.title = title
self.category = category
self.year = year
self.publisher = publisher
self.volume = volume
self.issue = issue
self.pages = pages
self.location = location
self.note = note
self.fullCitation = fullCitation
self.fullSource = fullSource
self.finalVersion = finalVersion
self.firstAuthor = firstAuthor
self.secondAuthor = secondAuthor
self.thirdAuthor = thirdAuthor
self.fourthAuthor = fourthAuthor
self.fifthAuthor = fifthAuthor
self.sixthAuthor = sixthAuthor
def __repr__(self):
return self.title
here is my view:
from flask import render_template, request, flash, redirect, url_for
from . import publications_blueprint
from .publicationsForm import PublicationsForm
from .publicationsModel import Publications
from app import db
#publications_blueprint.route("/publications", methods=["GET", "POST"])
def createPublications():
form = PublicationsForm(request.form)
publicationss = Publications.query.all()
if request.method == "POST" and form.validate_on_submit():
publications = Publications(form.title.data, form.category.data, form.year.data, form.publisher.data, form.volume.data, form.issue.data, form.pages.data, form.location.data, form.note.data, form.fullCitation.data, form.fullSource.data, form.finalVersion.data, form.firstAuthor.data, form.secondAuthor.data, form.thirdAuthor.data, form.fourthAuthor.data, form.fifthAuthor.data, form.sixthAuthor.data)
db.session.add(publications)
db.session.commit()
flash("Added Publications Successfully")
return redirect(url_for("publications.createPublications"))
return render_template("publications/publications.html", title="Publicationss", form=form, publicationss=publicationss)
#publications_blueprint.route("/updatePublications/<int:publications_id>", methods=["GET", "POST"])
def updatePublications(publications_id):
publications = Publications.query.get(publications_id)
form = PublicationsForm(request.form, obj=publications)
if request.method == "POST" and form.validate_on_submit():
publications.title = form.title.data
publications.category = form.category.data
publications.year = form.year.data
publications.publisher = form.publisher.data
publications.volume = form.volume.data
publications.issue = form.issue.data
publications.pages = form.pages.data
publications.location = form.location.data
publications.note = form.note.data
publications.fullCitation = form.fullCitation.data
publications.fullSource = form.fullSource.data
publications.finalVersion = form.finalVersion.data
publications.firstAuthor = form.firstAuthor.data
publications.secondAuthor = form.secondAuthor.data
publications.thirdAuthor = form.thirdAuthor.data
publications.fourthAuthor = form.fourthAuthor.data
publications.fifthAuthor = form.fifthAuthor.data
publications.sixthAuthor = form.sixthAuthor.data
db.session.commit()
flash("Updated Publications Successfully")
return redirect(url_for("publications.createPublications"))
publicationss = Publications.query.all()
return render_template("publications/publications.html", title="Publications", form=form, publicationss=publicationss)
#publications_blueprint.route("/deletePublications/<int:publications_id>", methods=["GET", "POST"])
def deletePublications(publications_id):
publications = Publications.query.get(publications_id)
db.session.delete(publications)
db.session.commit()
return redirect(url_for("publications.createPublications"))
In a similar case, I also use allow_blank=True in the model for a QuerySelectField search_target. I check manually if there was something selected in the view:
if formfilter.search_target.data:
search_target = formfilter.search_target.data.id
else:
....
I have one to many relationships between tables in a database and I want to get the data using an API.
I think that ma.Nested does not work because I don't get all the fields
can anyone help me?
I get only this :
[
{
"IsRef": false,
"commands": [
"299d7f0b-721c-484b-9448-072716a5fd70",
"382c5d9f-99a1-4aa2-ac30-96084e202fad",
"299d7f0b-721c-484b-9448-072716a5fd75",
"382c5d9f-99a1-4aa2-ac30-96084e202fak"
],
"filename": "uiyg",
"version": 8
}
]
this is the database model :
class File(db.Model):
id = db.Column(db.Integer, primary_key=True)
filename = db.Column(db.String(255), unique=True)
version = db.Column(db.Integer, unique=True)
IsRef = db.Column(db.Boolean)
commands = db.relationship('Command', backref='log', lazy='joined')
def __init__(self, filename, version, IsRef):
self.filename = filename
self.version = version
self.IsRef = IsRef
class Command(db.Model):
id_command = db.Column(db.String(255), primary_key=True, autoincrement=False)
name = db.Column(db.String(255))
log_id = db.Column(db.Integer, db.ForeignKey('file.id'))
status = db.Column(db.Boolean)
events = db.relationship('Event', backref='com', lazy='joined')
def __init__(self, id_command, name, log_id, status):
self.id_command = id_command
self.name = name
self.log = log_id
self.status = status
class Event(db.Model):
id_event = db.Column(db.Integer, primary_key=True)
event_name = db.Column(db.String(255))
seq_number = db.Column(db.Integer)
com_id = db.Column(db.Integer, db.ForeignKey('command.id_command'))
def __init__(self, event_name, seq_number, com_id):
self.event_name = event_name
self.seq_number = seq_number
self.com = com_id
this is the schema :
class EventSchema(ma.ModelSchema):
class Meta:
model = Event
fields = ('event_name', 'seq_number')
class CommandSchema(ma.ModelSchema):
class Meta:
model = Command
events = ma.Nested(EventSchema)
fields = ('id_command', 'name', 'status', 'events')
class LogSchema(ma.ModelSchema):
class Meta:
model = File
commands = ma.Nested(CommandSchema)
fields = ('filename', 'version', 'IsRef', 'commands')
Log_schema = LogSchema(many=True)
this is the API :
#app.route("/getall/<version>", methods=["GET"])
def get_all(version):
alle = File.query.filter_by(version=version)
return Log_schema.jsonify(alle)
this question is solved. I've changed 'lazy ='joined'' to 'lazy='dynamic'' and I've put ma.Nested out of the Meta class
I am trying to Update A Employee. I am able to update also. But the problem is coming a while updating when i am not sending data in body. It is giving error of Required Field.
This error is one of kind - where i was not sending excempt in json body
serializer2 {'excempt': [ErrorDetail(string='This field is required.', code='required')]}
Even i tried to put required=False and it is working but i am not understanding if we are passing instance of that EmployeeProfileSerializer(userprofile, data=request.data). Example userprofile but why it is still it is giving error. And how should i tackle it. I don't think this is the solution required=False?.
When i am not sending data in body then the previous data should be used but this is not happening instead it is giving error of required field
APIView
class EmployeeUpdateApiV2(APIView):
def post(self, request, *args, **kwrgs):
try:
accesstoken=AccessToken.objects.get(
token=self.request.META.get('HTTP_AUTHORIZATION').replace('Bearer ', '')
)
except ObjectDoesNotExist:
return Response (
{
"status" : False,
"error" : "Wrong Access Token",
"error_message":"You have provided wrong access token.",
}
)
user_id = request.data['user_id']
user = get_object_or_404(User, id=user_id)
print(user)
userprofile = get_object_or_404(UserProfile, user=user_id)
print(userprofile)
serializer1 = EmployeeRegisterSerializer(user, data=request.data)
serializer2 = EmployeeProfileSerializer(userprofile, data=request.data)
if serializer1.is_valid() and serializer2.is_valid():
serializer1.save()
serializer2.save()
print('Inside Valid')
return Response (
{
"status" : True,
"message":"Employee Updated Successfully.",
"api_name" : "EmployeeUpdateApiV2",
"result": serializer1.data,
"result1": serializer2.data,
}
)
print('Out Valid')
print('serializer1 ', serializer1.errors)
print('serializer2', serializer2.errors)
return Response(status=status.HTTP_404_NOT_FOUND)
Serializers.py
class EmployeeProfileSerializer(serializers.ModelSerializer):
employee_id = serializers.CharField(source='user_employee_id')
payroll_id = serializers.CharField(source='user_payroll_id')
hire_date = serializers.CharField(source='user_hire_date')
pay_rate = serializers.CharField(source='user_pay_rate')
salaried = serializers.CharField(source='user_salaried')
excempt = serializers.CharField(source='user_excempt')
groups = serializers.CharField(source='user_groups_id', required=False)
state = serializers.CharField(source='user_state')
city = serializers.CharField(source='user_city')
zipcode = serializers.CharField(source='user_zipcode')
status = serializers.CharField(source='user_status')
phone = serializers.CharField(source='user_phone')
class Meta:
model = UserProfile
fields = [
'employee_id',
'phone',
'payroll_id',
'hire_date',
'pay_rate',
'salaried',
'excempt',
'groups',
'state',
'city',
'zipcode',
'status',
]
class EmployeeRegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['first_name','last_name', 'email',]
Userprofile Model
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_company = models.ForeignKey(Company, on_delete=models.CASCADE)
user_role = models.ForeignKey(ACLRoles, on_delete=models.CASCADE)
user_dob = models.DateField(null=True, blank=True)
user_phone = models.CharField(max_length=30, blank=True, null=True)
user_image = models.ImageField(upload_to='user_profiles/', default='default_user.png',blank=True, null=True)
user_created = models.DateTimeField(auto_now_add=True)
user_is_deleted = models.BooleanField(default=False)
user_deleted_at = models.DateTimeField(blank=True, null=True)
user_groups = models.ManyToManyField(Groups,related_name='user_groups')
MALE = 'Male'
FEMALE = 'Female'
GENDER_CHOICES = (
(MALE, 'Male'),
(FEMALE, 'Female'),
)
user_gender = models.CharField(
max_length=8,
choices=GENDER_CHOICES,
)
ACTIVE = 'Active'
INACTIVE = 'Inactive'
PENDING = 'Pending'
USER_ACTIVE_CHOICES = (
(ACTIVE, 'Active'),
(INACTIVE, 'Inactive'),
(PENDING, 'Pending'),
)
user_status = models.CharField(
max_length=8,
choices=USER_ACTIVE_CHOICES,
default=ACTIVE,
)
please add user in your Model Serializer field section
class EmployeeProfileSerializer(serializers.ModelSerializer):
employee_id = serializers.CharField(source='user_employee_id')
payroll_id = serializers.CharField(source='user_payroll_id')
hire_date = serializers.CharField(source='user_hire_date')
pay_rate = serializers.CharField(source='user_pay_rate')
salaried = serializers.CharField(source='user_salaried')
excempt = serializers.CharField(source='user_excempt')
groups = serializers.CharField(source='user_groups_id', required=False)
state = serializers.CharField(source='user_state')
city = serializers.CharField(source='user_city')
zipcode = serializers.CharField(source='user_zipcode')
status = serializers.CharField(source='user_status')
phone = serializers.CharField(source='user_phone')
class Meta:
model = UserProfile
fields = [
'employee_id',
'phone',
'payroll_id',
'hire_date',
'pay_rate',
'salaried',
'excempt',
'groups',
'state',
'city',
'zipcode',
'status',
'user',
]