I have this model:
class State(ndb.Model):
code = ndb.StringProperty(required=True)
name = ndb.StringProperty(required=True)
city_list = ndb.StructuredProperty(City, repeated=True)
country = ndb.KeyProperty(required=True)
class City(ndb.Model):
code = ndb.StringProperty(required=True)
name = ndb.StringProperty(required=True)
I implemented this query:
stateData = State.query( State.city_list.name == 'xyz', State.name=='Punjab' ).fetch()
I want to implement query on State where name is Punjab. But Punjab has many cities, so I filtered by city name xyz.
I'm expecting only the xyz city but I'm getting all the cities in the result.
How can I get just the xyz city in the result?
You're querying for State kinds, so results will be State entities, with their complete city_list property - you can't get just a subset of the city_list. So what you're getting is expected.
You could maybe do a projection query, in which case you'd get a list of State entities, each with just a single city in city_list, see Projections and multiple-valued properties. Watch out for the limitations.
Or you could redesign your models, maybe with separate City entities you can query for directly (instead of structured properties inside the State entity).
you should filter before you fetch. the below syntax is based on an older version of ndb where you use Key property
class State(ndb.Model):
code = ndb.StringProperty(required=True)
name = ndb.StringProperty(required=True)
city_list = ndb.KeyProperty(kind=City, repeated=True)
country = ndb.KeyProperty(required=True)
stateq = State.query( State.name=='Punjab' )
city=stateq.filter(State.City==citykey)
result=city.fetch()
I did not try but it will probably work for structured property as well.
Related
My title may seem vague, but I'm sorry to save I have no other idea on how to phrase this. Assuming my model structure looks like this:
class Restaurant(models.Model):
name = models.CharField(...necessary stuff...)
class Cuisine(models.Model):
name = models.CharField(...necessary stuff...)
# thai chinese indian etc.
class Food(models.Model):
restaurant = models.ForeignKey(Restaurant, related_name='restaurant')
cuisine = models.ForeignKey(Cuisine, related_name='cuisine')
name = models.CharField(...)
What I want is a list of objects of Food of a specific restaurant. But the Food objects need to be under their respective Cuisine, so that I can easily access the Food through the context. Is it possible to achieve this in any way?
My current query:
q = Cuisine.objects.prefetch_related('cuisine')
q = q.filter(cuisine__restaurant_id=restaurant.id) # say restaurant.id=1
# here restaurant is the object which I have retrieved
Well, what it does is it filters the cuisines available to the restaurant, but lists all food within those cuisine. I want only the food available in the restaurant. I think I am missing something in the way I built my models, but I'm not certain. It would be really helpful if someone could point me to the right direction. Thanks.
Food.objects.filter(restuarant_id=1, cuisine_id__in=selected_cuisine_ids)
Here, selected_cuisine_ids is the list of IDs of whichever cuisines needed
In my opinion, you should use ManyToManyField with through argument. So your models should be like:
class Restaurant(models.Model):
name = models.CharField(...necessary stuff...)
cuisines = models.ManyToManyField(Restaurant, through='Food', related_name='restaurants')
class Cuisine(models.Model):
name = models.CharField(...necessary stuff...)
# thai chinese indian etc.
class Food(models.Model):
restaurant = models.ForeignKey(Restaurant, related_name='restaurant')
cuisine = models.ForeignKey(Cuisine, related_name='cuisine')
name = models.CharField(...)
In this way, your query would be like this:
Cuisine.objects.filter(restaurants__id=1)
I can't seem to isolate a single record from this query:
subcust = OwnerCustom.objects.get(carcustom=ncset, owner=sset)
This is the error:
OwnerCustom matching query does not exist
In the actual data, there is only actually one matching record in OwnerCustom for each record in CarCustom. It's supposed to be a kind of many-to-many where there are standard differences listed in CarCustom for each Car, and each owner may maintain their own customizations (overrides) or those default OwnerCustom entries.
Note, there are many different Owner of the same Car. And of course, I'm not actually doing cars, this is a renaming from the original purpose.
Here's the relevant models:
class Car(models.Model):
car_name = models.CharField(max_length=50)
class CarCustom(models.Model):
car = models.ForeignKey(Car, models.PROTECT)
class Owner(models.Model):
car = models.ForeignKey(Car, models.PROTECT)
class OwnerCustom(models.Model):
owner = models.ForeignKey(Owner, models.PROTECT)
carcustom = models.ForeignKey(CarCustom, models.PROTECT)
name = models.CharField(max_length=50)
And the code:
car_queryset = Car.objects.filter(car_name="fancy car")
for nset in car_queryset:
owner_queryset = Owner.objects.filter(car=nset)
for sset in owner_queryset :
carcustom_queryset = CarCustom.objects.filter(car=nset)
for ncset in carcustom_queryset:
subcust = OwnerCustom.objects.get(carcustom=ncset, owner=sset)
I've tried stuff like:
subcust = OwnerCustom.objects.filter(carcustom=ncset, owner=sset).first()
Which gives me a NoneType, and then tried:
subcust = OwnerCustom.objects.filter(carcustom=ncset, owner=sset)[:1].get()
Which gives "matching query does not exist" and this:
subcust = OwnerCustom.objects.filter(carcustom=ncset, owner=sset)[0]
Gives "list index out of range"
UPDATE: I CAN get a working function by using code like this, but I would think since there is only one (guaranteed by application) matching record possible for OwnerCustom.objects.filter(carcustom=ncset, owner=sset) that I could find a better way to fetch it:
car_queryset = Car.objects.filter(car_name="fancy car")
for nset in car_queryset:
owner_queryset = Owner.objects.filter(car=nset)
for sset in owner_queryset :
carcustom_queryset = CarCustom.objects.filter(car=nset)
for ncset in carcustom_queryset:
subcust_queryset = OwnerCustom.objects.filter(carcustom=ncset, owner=sset)
for subcust in subcust_queryset :
logger.info(subcust.name)
I have two models: City, and its alias CityAlias. The CityAlias model contains all the names in the City, plus the aliases. What I want is that whenever City is searched by name, the CityAlias model should be queried. This is what I've come up with:
class CityQuerySet(models.QuerySet):
""" If City is searched by name, search it in CityAlias """
def _search_name_in_alias(self, args, kwargs):
for q in args:
if not isinstance(q, models.Q): continue
for i, child in enumerate(q.children):
# q.children is a list of tuples of queries:
# [('name__iexact', 'calcutta'), ('state__icontains', 'bengal')]
if child[0].startswith('name'):
q.children[i] = ('aliases__%s' % child[0], child[1])
for filter_name in kwargs:
if filter_name.startswith('name'):
kwargs['aliases__%s' % filter_name] = kwargs.pop(filter_name)
def _filter_or_exclude(self, negate, *args, **kwargs):
# handles 'get', 'filter' and 'exclude' methods
self._search_name_in_alias(args=args, kwargs=kwargs)
return super(CityQuerySet, self)._filter_or_exclude(negate, *args, **kwargs)
class City(models.Model):
name = models.CharField(max_length=255, db_index=True)
state = models.ForeignKey(State, related_name='cities')
objects = CityQuerySet.as_manager()
class CityAlias(models.Model):
name = models.CharField(max_length=255, db_index=True)
city = models.ForeignKey(City, related_name='aliases')
Example: Kolkata will have an entry in City model, and it will have two entries in the CityAlias model: Kolkata and Calcutta. The above QuerySet allows to use lookups on the name field.
So the following two queries will return the same entry:
City.objects.get(name='Kolkata') # <City: Kolkata>
City.objects.get(name__iexact='calcutta') # <City: Kolkata>
So far so good. But the problem arises when City is a ForeignKey in some other model:
class Trip(models.Model):
destination = models.ForeignKey(City)
# some other fields....
Trip.objects.filter(destination__name='Kolkata').count() # some non-zero number
Trip.objects.filter(destination__name='Calcutta').count() # always returns zero
Django internally handles these joins differently, and doesn't call the get_queryset method of City's manager. The alternative is to call the above query as following:
Trip.objects.filter(destination=City.objects.get(name='Calcutta'))
My question is that can I do something, so that however the City model is searched by name, it always searches in the CityAlias table instead?
Or is there another better way to implement the functionality I require?
I think it is better (and more pythonic) to be explicit in what you ask for throughout instead of trying to do magic in the Manager and thus:
City.objects.get(aliases__name__iexact='calcutta') # side note: this can return many (same in original) so you need to catch that
And:
Trip.objects.filter(destination__aliases__name='Calcutta').count()
I was trying to use Custom Lookups but apparently you cannot add a table to the join list. (Well, you could add an extra({"table": ...}) in the model's manager but it's not an elegant solution).
So I'd propose you:
1) Keep always your 'main/preferred' name city also as a CityAlias. So the metadata of the city will be in City... but all the naming information will be in CityAlias. (and maybe change the names)
In this way all look-ups will happen in that table. You could have a boolean to mark which instance is the original/preferred.
class City(models.Model):
state = models.ForeignKey(State, related_name='cities')
[...]
class CityAlias(models.Model):
city = models.ForeignKey(City, related_name='aliases')
name = models.CharField(max_length=255, db_index=True)
2) If you are thinking about translations... Have you thought about django-modeltranslation app?
In this case, it would create a field for each language and it would be always better than having a join.
3) Or, if you are using PostgreSQL, and you are thinking about "different translations for the same city-name" (and I'm thinking with transliterations from Greek or Russian language), maybe you could use PostgreSQL dictionaries, trigrams with similarities, etc. Or even in this case, the 1st approach.
Speaking of keeping it simple. Why not just give the City model a char field 'CityAlias' that contains the string? If I understand your question correctly, this is the most simple solution if you only need one alias per city. It just looks to me as though you are complicating a simple problem.
class City(models.Model):
name = models.CharField(max_length=255, db_index=True)
state = models.ForeignKey(State, related_name='cities')
alias = models.CharField(max_length=255)
c = City.objects.get(alias='Kolkata')
>>>c.name
Calcutta
>>>c.alias
Kolkata
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 :)
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')]