Search by a property of a reference - python

I have the following models:
class Station(db.Model):
code = db.StringProperty(required=True)
name = db.StringProperty(required=True)
class Schedule(db.Model):
tripCode = db.StringProperty(required=True)
station = db.ReferenceProperty(Station, required=True)
arrivalTime = db.TimeProperty(required=True)
departureTime = db.TimeProperty(required=True)
How can I order programatically all the Schedules by Station's name?
Something like Schedule.all().order('station.name')

You will to de-normalize your models or sort the results in memory:
Schedule.all().fetch(100).sort(key=lambda s: s.station.name)
(code not tested)

After use sort i think you need to fetch all entities:
Schedule.all().fetch (100).sort(key=lambda s: s.station.name)
May be you can also use collection name.
But i think the jbochi answer is better :)
[x.schedule_set.get () for x in Station.all ().order ('name')]

Related

Peewee - Access an intermediary table easily

Say I have peewee models like so:
class Users(_BaseModel):
id = AutoField(primary_key=True, null=False, unique=True)
first_name = CharField(null=False)
last_name = CharField(null=False)
# Cut short for clarity
class Cohorts(_BaseModel):
id = AutoField(primary_key=True, null=False, unique=True)
name = CharField(null=False, unique=True)
# Cut short for clarity
class CohortsUsers(_BaseModel):
cohort = ForeignKeyField(Cohorts)
user = ForeignKeyField(Users)
is_primary = BooleanField(default=True)
I need to access easily from the user what cohort they are in and for example the cohort's name.
If a user could be in just one cohort, it would be easy but here, having it be many2many complicates things.
Here's what I got so far, which is pretty ugly and inefficient
Users.select(Users, CohortsUsers).join(CohortsUsers).where(Users.id == 1)[0].cohortsusers.cohort.name
Which will do what I require it to but I'd like to find a better way to do it.
Is there a way to have it so I can do Users.get_by_id(1).cohort.name ?
EDIT: I'm thinking about making methods to access them easily on my Users class but I am not really sure it's the best way of doing it nor how to go about it
If it do it like so, it's quite ugly because of the import inside the method to avoid circular imports
#property
def cohort(self):
from dst_datamodel.cohorts import CohortsUsers
return Users.select(Users, CohortsUsers).join(CohortsUsers).where(Users.id == self.id)[0].cohortsusers.cohort
But having this ugly method allows me to do Users.get_by_id(1).cohort easily
This is all covered in the documentation here: http://docs.peewee-orm.com/en/latest/peewee/relationships.html#implementing-many-to-many
You have a many-to-many relationship, where a user can be in zero, one or many cohorts, and a cohort may have zero, one or many users.
If there is some invariant where a user only has one cohort, then just do this:
# Get all cohorts for a given user id and print their name(s).
q = Cohort.select().join(CohortUsers).where(CohortUsers.user == some_user_id)
for cohort in q:
print(cohort.name)
More specific to your example:
#property
def cohort(self):
from dst_datamodel.cohorts import CohortsUsers
cohort = Cohort.select().join(CohortsUsers).where(CohortUsers.user == self.id).get()
return cohort.name

Check if object has relation with other in ManyToMany field and aggregate field

I have a couple models as follows:
class Student(models.Model):
name = models.CharField()
classes = models.ManyToManyField(Class, related_name="students")
class Class(models.Model):
nombre = models.CharField
What I need is a way such that, when querying students in certain class, instead of just returnig the students enrolled in that class, it returns a QuerySet of all the students, each one with an aggregated field indicating if such student is enrolled in that class, e.g.:
[{'name':'student A', 'enrolled_in_physics':True}, {'name':'student B', 'enrolled_in_physics':False}]
I think it can be achieved through F() expressions along with ExpressionWrapper, but have no idea of how implement them; additionaly, the documentation and the examples are not very noob-friendly. Any help is appreciated, thanks!.
EDIT: Ok, I think using the word "list" is not the correct one, I need a normal QuerySet, such that let me do something like this:
student_a = query[0]
student_a.name
>>>'A'
student_a.enrolled_in_physics
>>>True
UPDATED
You could try defining a method within the student class:
class Student(models.Model):
name = models.CharField()
classes = models.ManyToManyField(Class, related_name="students")
def enrolled_in_class(self,class_name):
if len(Class.objects.filter(nombre=class_name,students__in=self)) > 0:
return True
else:
return False
students = Student.objects.all()
student_a = students[0]
student_a.name
student_a.enrolled_in_class('physics')
Original Answer:
Edit: Sorry misread question, I'll try and get an answer together for what you actually wanted: A list of all students, and binary true false if they are enrolled in a specific class.
Alright, I'm reading this as a:
I need a query that returns a list of dictionaries, indicating the student, and enrollment in a class.
#Assume: class_name = 'physics'
def get_class_list(class_name):
filtered_class = Class.object.get(nombre=class_name)
student_names = Students.objects.filter(classes__contains=filtered_class).values_list('name',flat=True)
class_list = []
for name in student_names:
class_list = {}
class_list['name'] = name
enrolled_class_string = 'enrolled_in_' + class_name
class_list[enrolled_class_string] = True
return class_list
This will give you a list of dictionaries with the keys named 'name', and 'class__name'

Django query: Joining two models with two fields

I have the following models:
class AcademicRecord(models.Model):
record_id = models.PositiveIntegerField(unique=True, primary_key=True)
subjects = models.ManyToManyField(Subject,through='AcademicRecordSubject')
...
class AcademicRecordSubject(models.Model):
academic_record = models.ForeignKey('AcademicRecord')
subject = models.ForeignKey('Subject')
language_group = IntegerCharField(max_length=2)
...
class SubjectTime(models.Model):
time_id = models.CharField(max_length=128, unique=True, primary_key=True)
subject = models.ForeignKey(Subject)
language_group = IntegerCharField(max_length=2)
...
class Subject(models.Model):
subject_id = models.PositiveIntegerField(unique=True,primary_key=True)
...
The academic records have list of subjects each with a language code and the subject times have a subject and language code.
With a given AcademicRecord, how can I get the subject times that matches with the AcademicRecordSubjects that the AcademicRecord has?
This is my approach, but it makes more queries than needed:
# record is the given AcademicRecord
times = []
for record_subject in record.academicrecordsubject_set.all():
matched_times = SubjectTime.objects.filter(subject=record_subject.subject)
current_times = matched_times.filter(language_group=record_subject.language_group)
times.append(current_times)
I want to make the query using django ORM not with raw SQL
SubjectTime language group has to match with Subject's language group aswell
I got it, in part thanks to #Robert Jørgensgaard Eng
My problem was how to do the inner join using more than 1 field, in which the F object came on handly.
The correct query is:
SubjectTime.objects.filter(subject__academicrecordsubject__academic_record=record,
subject__academicrecordsubject__language_group=F('language_group'))
Given an AcademicRecord instance academic_record, it is either
SubjectTime.objects.filter(subject__academicrecordsubject_set__academic_record=academic_record)
or
SubjectTime.objects.filter(subject__academicrecordsubject__academic_record=academic_record)
The results reflect all the rows of the join that these ORM queries become in SQL. To avoid duplicates, just use distinct().
Now this would be much easier, if I had a django shell to test in :)

Django: Saving multiple ManyToMany fields within a transaction

this is the representation of my models:
class B(models.Model):
"""I'm a dummy model, so doesn't pay atention of what I do"""
name = models.CharField(max_length=250)
class A(models.Model):
name = models.CharField(max_length=250)
many_b = models.ManyToManyField(B)
Now, suppose I have a list of B objects. And a single A object that will be related to that Bs. Something like this:
a = A.objects.get(id=1)
list_of_b = [B<name='B1'>,B<name='B2'>,B<name='B3'>,]
The way I relate them now is this:
for b_object in list_of_b:
a.many_b.add(b_object)
Is there any way to add all the B objects in a single transaction? Maybe in a single method, like:
a.many_b.addList(b) #This doesn't exist
From the docs:
>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)
So if you have a list, use argument expansion:
a.many_b.add(*list_of_b)
I guess what you want is a kind of bulk insert right?
As far as I know this is just available in the Django TRUNK not in 1.3!
check it out some tutorial:
http://www.caktusgroup.com/blog/2011/09/20/bulk-inserts-django/

Google App Engine: how can I programmatically access the properties of my Model class?

I have a model class:
class Person(db.Model):
first_name = db.StringProperty(required=True)
last_name = db.StringProperty(required=True)
I have an instance of this class in p, and string s contains the value 'first_name'. I would like to do something like:
print p[s]
and
p[s] = new_value
Both of which result in a TypeError.
Does anybody know how I can achieve what I would like?
If the model class is sufficiently intelligent, it should recognize the standard Python ways of doing this.
Try:
getattr(p, s)
setattr(p, s, new_value)
There is also hasattr available.
With much thanks to Jim, the exact solution I was looking for is:
p.properties()[s].get_value_for_datastore(p)
To all the other respondents, thank you for your help. I also would have expected the Model class to implement the python standard way of doing this, but for whatever reason, it doesn't.
getattr(p, s)
setattr(p, s, new_value)
Try:
p.model_properties()[s].get_value_for_datastore(p)
See the documentation.
p.first_name = "New first name"
p.put()
or p = Person(first_name = "Firsty",
last_name = "Lasty" )
p.put()

Categories

Resources