Django: How to deal with model subclassing and IntegrityErros? - mysql

I have this in my models.py
class Page(models.Model)
#fields
class News(Page)
#no fields
class NewsComment(models.Model)
news = models.Foreignkey(news)
name = models.CharField(max_length=128)
email = models.EmailField(max_length=75)
comment = models.TextField()
Every time I am trying this:
page = get_object_or_404(News, id=page_id)
and then
comment, created = NewsComment.objects.get_or_create(news=page, name=name, email=email, comment=text)
I get this error:
(1452, 'Cannot add or update a child row: a foreign key constraint fails (myproject_db.main_newscomment, CONSTRAINT news_id_refs_page_ptr_id_5a5b8a6204eece43 FOREIGN KEY (news_id) REFERENCES main_news (page_ptr_id))')
What am I doing wrong?
(PS: I am using MySQL with InnoDB storage engine)

If the News model has no fields you should implement the inheritance using a proxy model. It will lead to much simpler database schema, and much simpler and faster (!) queries. It will also eliminate most problems dealing with how model inheritance is implemented on the database level.
class Page(models.Model)
#fields
class News(Page)
class Meta:
proxy = True

Related

When do you actually use multiple foreign keys?

I want to create tables where one has multiple foreign keys of the other. Then I want relationships between the two using the foreign_keys argument.
class Trial(SurrogatePK, Model):
__tablename__ = 'trials'
challenges = relationship('Challenge', foreign_keys='[Challenge.winner_id, '
'Challenge.loser_id]')
class Challenge(SurrogatePK, Model):
__tablename__ = 'challenges'
winner_id = reference_col('trials')
winner = relationship('Trial', back_populates='challenges',
foreign_keys=winner_id)
loser_id = reference_col('trials')
loser = relationship('Trial', back_populates='challenges',
foreign_keys=loser_id)
This doesnt work because sqlachemy gets two foreign_keys and gives an error for that.
The way to make it work is with a primaryjoin:
class Trial(SurrogatePK, Model):
__tablename__ = 'trials'
challenges = relationship('Challenge', primaryjoin=
'or_(Trial.id==Challenge.winner_id,'
'Trial.id==Challenge.loser_id)')
Now, the thing that I want to ask is. When should I actually use multiple foreign keys in the foreign_keys argument. It's got to be plural for a reason right?
In the entire documentation I can't find a singel case where they are actually using multiple foreign keys.

django router forgets the DB while pointing to ForeignKey

My mobileapp is going to be used by different schools( with different db but same structure).Logged in user(parent) will be connected with multiple db(if their two child in different schools) using DynamicDbRouter. Now the problem is django router forgets the DB while pointing to ForeignKey.
views.py
class StudentFees(LoginRequiredMixin,TemplateView):
template_name = 'student_fees.html'
def get_context_data(self,**kwargs):
context = super(StudentFees,self).get_context_data(**kwargs)
schl_id=kwargs['schl_id']
school_id=School.objects.get(id=kwargs['schl_id'])
with in_database(school_id) :
context['classes'] = StudentSection.objects.filter(student_detail=kwargs['student_id'])
context['invoices'] = Invoice.objects.filter(student_master=kwargs['student_id'],status=1)
print context
return context
Here student_detail & student_master are foreign key fields.
routers.py
class in_database(object):
def __init__(self, client, read=True, write=False):
...
database = {'ENGINE':'django.db.backends.mysql','NAME':client.db_name,'USER':client.username,'PASSWORD':client.password,'HOST':client.host,'PORT':client.port}
...
Instead of pointing to client_db.model it points to default_db.model while accessing foreign keys.
I can able to see context details in console.. but values not redering in student_fees.html. It throws error like
ProgrammingError :
default_db.studentsection' doesn't exist

Passive deletes in SQLAlchemy with a many-to-many relationship don't prevent DELETE from being issued for related object

I am trying to get SQLAlchemy to let my database's foreign keys "on delete cascade" do the cleanup on the association table between two objects. I have setup the cascade and passive_delete options on the relationship as seems appropriate from the docs. However, when a related object is loaded into the collection of a primary object and the primary object is deleted from the session, then SQLAlchemy issues a delete statement on the secondary table for the record relating the primary and secondary objects.
For example:
import logging
import sqlalchemy as sa
import sqlalchemy.ext.declarative as sadec
import sqlalchemy.orm as saorm
engine = sa.create_engine('sqlite:///')
engine.execute('PRAGMA foreign_keys=ON')
logging.basicConfig()
_logger = logging.getLogger('sqlalchemy.engine')
meta = sa.MetaData(bind=engine)
Base = sadec.declarative_base(metadata=meta)
sess = saorm.sessionmaker(bind=engine)
session = sess()
blog_tags_table = sa.Table(
'blog_tag_map',
meta,
sa.Column('blog_id', sa.Integer, sa.ForeignKey('blogs.id', ondelete='cascade')),
sa.Column('tag_id', sa.Integer, sa.ForeignKey('tags.id', ondelete='cascade')),
sa.UniqueConstraint('blog_id', 'tag_id', name='uc_blog_tag_map')
)
class Blog(Base):
__tablename__ = 'blogs'
id = sa.Column(sa.Integer, primary_key=True)
title = sa.Column(sa.String, nullable=False)
tags = saorm.relationship('Tag', secondary=blog_tags_table, passive_deletes=True,
cascade='save-update, merge, refresh-expire, expunge')
class Tag(Base):
__tablename__ = 'tags'
id = sa.Column(sa.Integer, primary_key=True)
label = sa.Column(sa.String, nullable=False)
meta.create_all(bind=engine)
blog = Blog(title='foo')
blog.tags.append(Tag(label='bar'))
session.add(blog)
session.commit()
# sanity check
assert session.query(Blog.id).count() == 1
assert session.query(Tag.id).count() == 1
assert session.query(blog_tags_table).count() == 1
_logger.setLevel(logging.INFO)
session.commit()
# make sure the tag is loaded into the collection
assert blog.tags[0]
session.delete(blog)
session.commit()
_logger.setLevel(logging.WARNING)
# confirm check
assert session.query(Blog.id).count() == 0
assert session.query(Tag.id).count() == 1
assert session.query(blog_tags_table).count() == 0
The above code will produce DELETE statements as follows:
DELETE FROM blog_tag_map WHERE
blog_tag_map.blog_id = ? AND blog_tag_map.tag_id = ?
DELETE FROM blogs WHERE blogs.id = ?
Is there a way to setup the relationship so that no DELETE statement for blog_tag_map is issued? I've also tried setting passive_deletes='all' with the same results.
Here, the “related object” is not being deleted. That would be “tags”. The blog_tags_table is not an object, it is a many-to-many table. Right now the passive_deletes='all' option is not supported for many-to-many, that is, a relationship that includes "secondary". This would be an acceptable feature add but would require development and testing efforts.
Applying viewonly=True to the relationship() would prevent any changes from affecting the many-to-many table. If the blog_tags_table is otherwise special, then you'd want to use the association object pattern to have finer grained control.

Django unique_together not working

I can't get Django (1.5) to create MySQL UNIQUE indexes on 3 columns, even though I've followed every suggestion I found on SO. Here's how my model looks like:
class Loc(models.Model):
rand = models.IntegerField()
sectiune = models.ForeignKey(Sectiune)
numar = models.IntegerField()
pret = models.FloatField()
def __unicode__(self):
return str(self.sectiune.nume) + ': R' + str(self.rand) + ' L' + str(self.numar)
class Meta:
unique_together = (("rand","sectiune","numar"),)
I really don't get what's wrong. I've seen a bug report that unique_together doesn't work on foreign keys, but I've also seen that has been fixed. Any help?
Turns out Django is not that smart after all... It doesn't know how to ALTER a table to create the UNIQUE constraint. I just had to delete the tables, run syncdb again, and the constraints were there :)

Programmatically identify django foreignkey links

Similar to the question I asked here, if I wanted to list all of the foreign key relationships from a model, is there a way to detect these relationships (forward and backward) automatically?
Specifically, if Model 1 reads
class Mdl_one(models.Model):
name = models.CharField(max_length=30)
and Model 2 reads
class Mdl_two(models.Model):
mdl_one = models.ForeignKey(Mdl_one)
name = models.CharField(max_length=30)
Is there some meta command I can run from Mdl_one (like Model_one()._meta.one_to_many) that tells me that mdl_two has a one-to-many foreign key relationship with it? Simply that mdl_one and mdl_two can be connected, not necessarily that any two objects actually are?
This is you are looking for:
yourModel._meta.get_all_related_objects()
Sample (Edited):
class Alumne(models.Model):
id_alumne = models.AutoField(primary_key=True)
grup = models.ForeignKey(Grup, db_column='id_grup')
nom_alumne = models.CharField("Nom",max_length=240)
cognom1alumne = models.CharField("Cognom1",max_length=240)
cognom2alumne = models.CharField("Cognom2",max_length=240, blank=True)
...
class Expulsio(models.Model): <---!
alumne = models.ForeignKey(Alumne, db_column='id_alumne')
dia_expulsio = models.DateField(blank=True)
...
>>> from alumnes.models import Alumne as A
>>> for x in A._meta.get_all_related_objects():
... print x.name
...
horaris:alumneexclosdelhorari
presencia:controlassitencia
incidencies:entrevista
incidencies:expulsio <---!
incidencies:incidencia
incidencies:incidenciadaula
seguimentTutorial:seguimenttutorial