Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid inserting duplicate entries when adding values via a sqlalchemy relationship?

Let's assume we have two tables in a many to many relationship as shown below:

class User(db.Model):
  __tablename__ = 'user'
  uid = db.Column(db.String(80), primary_key=True)
  languages = db.relationship('Language', lazy='dynamic',
                              secondary='user_language')

class UserLanguage(db.Model):
  __tablename__ = 'user_language'
  __tableargs__ = (db.UniqueConstraint('uid', 'lid', name='user_language_ff'),)

  id = db.Column(db.Integer, primary_key=True)
  uid = db.Column(db.String(80), db.ForeignKey('user.uid'))
  lid = db.Column(db.String(80), db.ForeignKey('language.lid'))

class Language(db.Model):
  lid = db.Column(db.String(80), primary_key=True)
  language_name = db.Column(db.String(30))

Now in the python shell:

In [4]: user = User.query.all()[0]

In [11]: user.languages = [Language('1', 'English')]

In [12]: db.session.commit()

In [13]: user2 = User.query.all()[1]

In [14]: user2.languages = [Language('1', 'English')]

In [15]: db.session.commit()

IntegrityError: (IntegrityError) column lid is not unique u'INSERT INTO language (lid, language_name) VALUES (?, ?)' ('1', 'English')

How can I let the relationship know that it should ignore duplicates and not break the unique constraint for the Language table? Of course, I could insert each language separately and check if the entry already exists in the table beforehand, but then much of the benefit offered by sqlalchemy relationships is gone.

like image 924
Paul Baltescu Avatar asked Dec 30 '13 00:12

Paul Baltescu


1 Answers

The SQLAlchemy wiki has a collection of examples, one of which is how you might check uniqueness of instances.

The examples are a bit convoluted though. Basically, create a classmethod get_unique as an alternate constructor, which will first check a session cache, then try a query for existing instances, then finally create a new instance. Then call Language.get_unique(id, name) instead of Language(id, name).

I've written a more detailed answer in response to OP's bounty on another question.

like image 147
davidism Avatar answered Sep 20 '22 23:09

davidism