Joined selection from two tables - mysql

I'm using Django with a mysql database.
I have the table Question that contains the fields: id, text, section_id and I have the table CompletedQuestion that has the fields: id, question_id where the field question_id is foreign key to Question.id.
My models.py contains:
class Question(mixins.OrdMixin, mixins.EqMixin, models.Model):
section = models.ForeignKey('Section',
on_delete=models.CASCADE,
related_name='owner')
text = models.TextField()
class CompletedQuestion(models.Model):
question = models.ForeignKey('Question',
on_delete=models.CASCADE,
related_name='question_source')
I want to check whether there are completed questions in CompletedQuestion where belong to a specific section_id from Question.
My current query is the following but it's not the proper one:
quest_id = Question.objects.filter(section_id = section_id)

There is the __isnull=True|False filter you can use to check if any related model exists, I dont really understand what you mean but something like:
Question.objects.filter(section_id=section_id, question_source__isnull=False)
Or come from the other direction like:
CompletedQuestion.objects.filter(question__section_id=section_id) \
.values_list("question_id",flat=True).distinct()
To get a list of question-IDs that have any related CompletedQuestions

Related

Django ORM: Tried to do inner join with foreign key but causes FieldError

I am new to django orm.
I've tables look like this.
class Product(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=60)
class ProductOption(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
product_id = models.ForeignKey(Product, on_delete=models.CASCADE, null=True, blank=True)
I would like to query productoption id that related to product. I made query like this to do inner join.
Query = Product.select_related(‘product_id’).filter(name='a')
And it gaves me error message saying
django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'product_id'. Choices are: (none)
I want to know if there is something wrong in models or query.
Use prefetch_related
Product.objects.filter(name='a').prefetch_related('productoption_set')
This is not how you query a related object. Since you used a foreign key and if I understand correctly, you probably want to use something like this:
Product.objects.filter(name='a').productoption_set.all()

Django - How to GET value from table where I don't have foreign key in table from which I want to GET object?

Let's assume that I have for instance table Object1 with columns id,id_users where id_users is a foreign key of id from auth_user table and table Object2 with columns id,id_object1,sth, where id_object1 is a foreign key of id from Object1 table.ID of Object1 and Object2 is automatically incremented in mySQL database.
I would like to have for instance such URL /users/{id}/object2/?sth=123 and I would like to get object from Object2 table where {id} is id of the user from auth_user table (in this case is equals 2) and sth is equals 123 in Object2 table in appropriate field.
Let's assume this is my model:
class Object1(models.Model):
id_users = models.PositiveIntegerField(blank=True)
class Object2(models.Model):
id_object1 = models.FloatField()
sth = models.FloatField()
I had quite similar problem which was solved in this post - Django - How can I create POST with foreign key defined in URL? but in this case I don't have foreign key in table from which I want to GET object. I have no idea what is the best way to solve this problem. Thanks in advance.
From what I understand about your dilemma, I think your models should be somewhat like this,
models.py
class Object1(models.Model):
id_users = models.ForeignKey(User)
class Object2(models.Model):
id_object1 = models.ForeignKey(Object1)
sth = models.FloatField()
Then, you asked that the urls should look somewhat like this,
/users/{id}/object2/?sth=123
Then your view should be somewhat like this,
views.py
def your_view(request, user_id):
sth = request.GET.get('sth', '')
sth_instance = Object2.objects.get(sth=sth, object1__id_users=request.user)
#do whatever you want to do...
urls.py
urlpatterns = [
url(r'^users/(?P<user_id>[\d]*)/object2/$', your_view, name='view_name'),
]
Hope this what you were looking for..

Two "one-to-one" references to same table in SQLAlchemy

Suppose I am modelling postal address changes. I'd like each AddressChange to have a before relationship to an Address, as well as an after relationship to another Address. And I'd like a reference back from the Address to the AddressChange it is associated with.
class AddressChange(Base):
__tablename__ = 'AddressChanges'
id = Column(Integer, primary_key=True)
before_id = Column(Integer, ForeignKey('Addresses.id'))
before = relationship('Address', foreign_keys=before_id, uselist=False,
back_populates='change')
after_id = Column(Integer, ForeignKey('Addresses.id'))
after = relationship('Address', foreign_keys=after_id, uselist=False,
back_populates='change')
class Address(Base):
__tablename__ = 'Addresses'
id = Column(Integer, primary_key=True)
street, city, etc = Column(String), Column(String), Column(String)
change = relationship('AddressChange')
However SQLAlchemy complains:
Could not determine join condition between parent/child tables on relationship Address.change - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
My Address does not have a foreign key reference to the parent table, and it's not clear to me why it should need one. If I add one, I get
Address.change and back-reference AddressChange.before are both of the same direction symbol('MANYTOONE'). Did you mean to set remote_side on the many-to-one side ?
Which is starting to get confusing, because the documentation for remote_side is for "self-referential relationships."
Thanks to #alex-grönholm for helping on #sqlalchemy.
This can be solved by adding a primaryjoin parameter to Address's side of the relationship to teach it how to map back to the parent AddressChange:
change = relationship('AddressChange', uselist=False,
viewonly=True,
primaryjoin=or_(
AddressChange.before_id == id,
AddressChange.after_id == id
))

Remove duplicate entries in peewee

I have a quick function that I threw up together to remove duplicates on my table given a particular combination of fields:
for l in table.select():
if table.select().where((table.Field1==l.Field1) & (table.Field2==l.Field2) & ....).count()>1:
l.delete()
l.save()
But I imagine that there's a better way to do this
You could add a unique constraint on the columns you wish to be unique, then let the database enforce the rules for you. That'd be the best way.
For peewee, that looks like:
class MyModel(Model):
first_name = CharField()
last_name = CharField()
dob = DateField()
class Meta:
indexes = (
(('first_name', 'last_name', 'dob'), True),
)
Docs: http://docs.peewee-orm.com/en/latest/peewee/models.html#indexes-and-unique-constraints

expanding the SQL query inside managers in Django models?

Here is the code from django docs that explains the use of managers.
class PollManager(models.Manager):
def with_counts(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute("""
SELECT p.id, p.question, p.poll_date, COUNT(*)
FROM polls_opinionpoll p, polls_response r
WHERE p.id = r.poll_id
GROUP BY p.id, p.question, p.poll_date
ORDER BY p.poll_date DESC""")
result_list = []
for row in cursor.fetchall():
p = self.model(id=row[0], question=row[1], poll_date=row[2])
p.num_responses = row[3]
result_list.append(p)
return result_list
class OpinionPoll(models.Model):
question = models.CharField(max_length=200)
poll_date = models.DateField()
objects = PollManager()
class Response(models.Model):
poll = models.ForeignKey(OpinionPoll)
person_name = models.CharField(max_length=50)
response = models.TextField()
I have two questions based on this code:
1) where is r.poll_id coming from? I understand Response has foreignKey relationship to OpinionPoll. In order to JOIN OpinionPoll table with Response table, I need to join on their id.
HOwever to access the poll id in Response, I would do r.poll.id.
Is the syntax, r.poll_id, a MySQL syntax.
why GROUP BY p.id, p.question, p.poll_date? why GROUP BY p.id alone is not sufficient?
2) Is it possible to turn the above raw SQL query into a django ORM query?If so how would that look like?
I am not a SQL guy. so bear with me, if this sounds stupid
EDIT:
If I want to create OpinionPoll and Response tables outside of Django, how will SQL statment for create look like?
In the Django shell, when I run
python manage.py sqlall appname
I get the following:
BEGIN;
CREATE TABLE "myapp_opinionpoll" (
"id" integer NOT NULL PRIMARY KEY,
"question" varchar(200) NOT NULL,
"poll_date" date NOT NULL
)
;
CREATE TABLE "myapp_response" (
"id" integer NOT NULL PRIMARY KEY,
"poll_id" integer NOT NULL REFERENCES "myapp_opinionpoll" ("id"),
"person_name" varchar(50) NOT NULL,
"response" text NOT NULL
)
;
CREATE INDEX "larb_response_70f78e6b" ON "myapp_response" ("poll_id");
COMMIT;
I see something like REFERENCES "myapp_opinionpoll" and CREATE INDEXabove. I am not sure
if this is how in SQL it is done?
[1] Django model will create foreign keys like fieldname_id as the field in mysql. So you see the field poll = models.ForeignKey(OpinionPoll) creates this field.
About GROUP BY, because these fields are exactly what selected, except for the aggregate function, grouping them exactly can make them distinct.
[2] Try this, I didn't debug, but may helps:
from django.db.models import Count
OpinionPoll.objects.annotate(num_responses=Count('response'))
For more about aggregation, see the docs: https://docs.djangoproject.com/en/1.6/topics/db/aggregation/