Reputation: 1
I have three tables. User, listitem and Song. User and listitem have Many-to-Many relationship with a table songcart. and listitem has one to many relationship with Song. whenever I add a listitem to user.cart, as long as its a different item, there is no problem in displaying it on the table. Once same item is added to the cart, title for the previous item becomes blank.
Picture
shows the resulted frontend html, and frontend source code comes blank <div class="col-3"> </div>
. It happens only for the copies of same item.
Here is my code: models.py
songcart = db.Table('Songcart',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('listitem_id', db.Integer, db.ForeignKey('listitem.id')),
)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
...
cart = db.relationship('ListItem', secondary=songcart, backref=db.backref('owner', lazy='dynamic'))
class ListItem(db.Model):
__tablename__ = 'listitem'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(140))
song = db.relationship('Song', backref='inlist', lazy='dynamic')
...
listorder = db.Column(db.Integer)
...
role = db.relationship('User', secondary=rolestable, backref=db.backref('roles', lazy='dynamic'), lazy='dynamic') # second relationship is to later assign a person to specific item.
def __repr__(self):
return '<ListItems {}>'.format(self.title)
class Song(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
lyrics = db.Column(db.Text)
language = db.Column(db.Integer)
routes.py
@app.route('/add_to_cart', methods=['POST'])
@login_required
def add_to_cart():
songid = request.args.get('songid', type=int)
user = User.query.filter_by(username=current_user.username).first_or_404()
song = Song.query.get_or_404(songid)
cart = [c for c in current_user.cart]
cartitem = ListItem(title=song.title, desired_key=song.key, listorder=len(cart)+1)
cartitem.song.append(song)
user.cart.append(cartitem)
db.session.add(cartitem)
db.session.add(user)
db.session.commit()
# need to finish
return redirect(url_for('songbook'))
@app.route('/cart/<username>', methods=['GET', 'POST'])
@login_required
def cart(username):
user = User.query.filter_by(username=username).first_or_404()
users = User.query.all()
form = EmptyForm()
e_form = EmptyForm()
unroleform = EmptyForm()
deleteform = EmptyForm()
# songlist = [item for item in user.cart.sort(key=lambda x: x.listorder)]
sl = sorted(user.cart, key=lambda x: x.listorder)
songlist = [item for item in sl]
for l in songlist:
if l.listorder is None:
l.listorder = l.id
# db.session.add(l)
db.session.commit()
print(l)
return render_template('cart.html', songlist=songlist, form=form, deleteform=deleteform, keyset=keyset, users=users, e_form=e_form, unroleform=unroleform)
cart.html here I am using sortable jquery, drag and drop.
{% extends "base.html" %}
{% block head_js %}
<script src="{{ url_for('static', filename='/js/jquery-3.6.0.min.js') }}"></script>
<script src="{{ url_for('static', filename='/js/jquery-ui.min.js') }}"></script>
<style>
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
#sortable {
list-style-type: none;
margin: 0;
padding: 0;
}
#sortable li {
margin: 3px;
padding: 0.4em;
padding-left: 0.2em;
font-size: 1em;
height: 30px;
cursor: grab;
}
</style>
<script>
$(function() {
$("#sortable").sortable({
update: function(event, ui) {
var order = [];
$("#sortable li").each(function(index) {
order.push($(this).data("item-id"));
});
$.ajax({
url: "/cart_update-list-order",
type: "POST",
data: { order: order },
success: function(response) {
console.log(response);
},
error: function(xhr, status, error) {
console.error(error);
}
});
}
});
$("#sortable").disableSelection();
});
function changeDesiredKey(itemId, newDesiredKey) {
// Send the updated desired key to the backend using AJAX
...
}
function updateNotes(itemId, event) {
...
}
function assignUser(itemId) {
var userId = $("#user_" + itemId).val();
// Send the updated assigned user to the backend using AJAX
...
}
</script>
{% endblock %}
{% block app_content %}
<br>
<div class="row">
<div class="col">
<nav class="nav nav-pills justify-content-end">
<a class="nav-link active" aria-current="page" href="{{url_for('assign2event') }}">Add to service</a>
<form action="{{ url_for('empty_cart') }}" method="post">
{{ e_form.hidden_tag() }}
{{ e_form.submit(class_='btn btn-secondary', value='Empty') }}
</form>
</nav>
</div>
</div>
<br>
<div class="row">
<div class="col">
<ul><li>
<div class="row border-bottom border-3 bg-light text-dark">
<div class="col-auto"><strong>No.</strong></div>
<div class="col-3"><strong>Title</strong></div>
<div class="col-auto"><strong> Key </strong></div>
...
</div></li></ul>
<ul id="sortable">
{% for s in songlist %}
<li data-item-id="{{ s.id }}">
<div class="row bg-light text-dark">
<div class="col-auto">{{ s.id }}</div>
<div class="col-3">
{% for song in s.song %}
<a href="{{ url_for('.view_song', id=song.id) }}">{{ song.title }}</a>
{% endfor %}
</div>
<div class="col-1">
<select class="form-select form-select-sm" onchange="changeDesiredKey('{{ s.id }}', this.value)">
{% for key in keyset %}
<option value="{{ loop.index0 }}" {% if s.desired_key == loop.index0 %}selected{% endif %}>{{ key }}</option>
{% endfor %}
</select>
</div>
...
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endblock %}
Could anyone please point where should I look for issues? Is it js? or is it the issue with my models.py?
checked backend both in shell and during server run. even printed in console variables like songlist and each iteration of songlist. data is there.
Update
Have changed relationship of ListItem and Song table from O-M into M-M. and everything started working.
now it properly shows all titles. Stupid mistake from my part.
have been thoroughly searching in wrong places for several days. Out of curiosity decided to try M-M relationship, and it solved the issue. I am new to Flask and sqlalchemy. Thus only now I'm beginning to understand the relationship. one to many didn't work, as once song is assigned to that list, it can no longer be associated with another listitem.
If I established M-O relationship between listitem and song whould've it also solved my issue?
Upvotes: 0
Views: 54