I'm trying to do a reverse key query. The query is this: the foo elements that has the biggest quantity of bar.
Foo:
name = models.CharField('name', max_length=255)
Bar:
name = models.CharField('name', max_length=255)
foo = models.ForeignKey(Foo)
foo_1.name = foo1
foo_2.name = foo2
foo_3.name = foo3
bar_1.name = bar1
bar_1.foo = foo1
bar_2.name = bar2
bar_2.foo = foo2
bar_3.name = bar3
bar_3.foo = foo2
bar_4.name = bar4
bar_4.foo = foo3
bar_4.name = bar4
bar_4.foo = foo3
'Foo2' has 2 'bars' and 'foo3' has 2 'bars' while 'foo1' has only one 'bar'
the result i want is a list with the foos with the biggest quantity of bars and the qty of bars like this:
[{'foo': foo2, 'qty_of_bars': 2}, {'foo': foo3, 'qty_of_bars': 3}]
I've tried a lot of things, for example:
foos = Foo.objects.all()
foos_with_biggest_qty_of_bar = foo.annotate(bar_count=Count('bar')).order_by(
'-bar_count').first()
This gives only one foo, the one with the biggest qty of bars, for example 'foo3', but there may be more than one. In the case above there are 2, foo2 and foo3.
I've tried this:
foos_with_biggest_qty_of_bar = foo.annotate(bar_count=Count('bar')).order_by(
'-bar_count').first()
This gives me the biggest qty of bars related to one single foo
biggest_qty_of_bars = bars.objects.filter(foo=foos_with_biggest_qty_of_bar ).count()
foos_with_biggest_qty_of_bars = Foo.objects.all().annotate(total_bars=biggest_qty_of_bars )
This last line didnt work, i got:
'int' object has no attribute 'lookup'
I tried other thing with a for loop(it's terrible, very ugly, sorry guys for this, by it was an attempt on despair, it's driving me crazy):
qyt_of_bars_of_each_foo = Foo.object.values('name').annotate(
count_bar=Count('bar'))
biggest_number = 0
foo_with_biggest_number_of_bar = []
for qty_of_bar_of_foo in qyt_of_bars_of_each_foo :
if qyt_of_bars_of_each_foo ['count_bar'] >= biggest_number :
foo_with_biggest_number_of_bar .append(qty_of_bar_of_foo)
biggest_number = qyt_of_bars_of_each_foo ['count_bar']
Nothing gave me the result I wanted, which is a list with the foos with the biggest quantity of bars and the qty, like I said before. I'm still trying but as I said it's driving me Crazy, i'm stuck on it since yesterday. Any help I would appreciate a lot!!
Have you tried doing an annotation over the entire queryset using Count and then returning the values as a list?
foo_objects = Foo.objects.all().annotate(
qty_of_bars=Count('bar')).order_by('-qty_of_bars').values(
'name', 'qty_of_bars')
This would return a list, e.g.:
[{'name': u'Foo1', 'qty_of_bars': 3}, {'name': u'Foo2', 'qty_of_bars': 2}]
given an app module name of 'foo' and the following fixture data:
[{
"fields": {
"name": "Foo1"
},
"model": "foo.foo",
"pk": 1
}, {
"fields": {
"name": "Foo2"
},
"model": "foo.foo",
"pk": 2
}, {
"fields": {
"foo": 1,
"name": "Bar1-1"
},
"model": "foo.bar",
"pk": 1
}, {
"fields": {
"foo": 1,
"name": "Bar2-1"
},
"model": "foo.bar",
"pk": 2
}, {
"fields": {
"foo": 1,
"name": "Bar3-1"
},
"model": "foo.bar",
"pk": 3
}, {
"fields": {
"foo": 2,
"name": "Bar1-2"
},
"model": "foo.bar",
"pk": 4
}, {
"fields": {
"foo": 2,
"name": "Bar2-2"
},
"model": "foo.bar",
"pk": 5
}]
update
If you're needing to get to values where qt_of_bars is greater than 1, you can easily get to those via a list comprehension, since you can't filter on an annotated field via the ORM:
foo_objects = [{'foo': f, 'qty_of_bars': f.qty_of_bars}
for f in Foo.objects.all().annotate(
qty_of_bars=Count('bar')).order_by(
'-qty_of_bars') if f.qty_of_bars > 1]
[{'foo': <Foo: Foo1>, 'qty_of_bars': 3}, {'foo': <Foo: Foo2>, 'qty_of_bars': 2}]
Related
Say I have the common pizza example:
class Topping(models.Model):
order = models.IntegerField()
name = models.CharField(max_length=250)
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
With the following toppings:
Topping.objects.create(order=1, name="tomato")
Topping.objects.create(order=2, name="cheese")
Topping.objects.create(order=3, name="olives")
Topping.objects.create(order=4, name="salami")
Topping.objects.create(order=5, name="onion")
Topping.objects.create(order=6, name="rocket")
Now say I had a pizza with tomato, cheese and salami.
I wish to get an order list of all the toppings of the pizza according to the topping__order, along with a list of all the toppings it does not have, also ordered by topping__order.
So it's sorted by first where the pizza has the topping, and secondly by the topping__order field.
The result would be something that has the same info as this (probably in a queryset though):
{
{ "id": 1, "name": "tomato", "has_topping": True},
{ "id": 2, "name": "cheese", "has_topping": True},
{ "id": 3, "name": "salami", "has_topping": True},
{ "id": 2, "name": "olives", "has_topping": False},
{ "id": 5, "name": "onion" , "has_topping": False},
{ "id": 6, "name": "rocket", "has_topping": False},
}
Is this possible via a database query? (I can do it manually in Python via two queries)
You can do it with .order_by() function:
Pizza.objects.all().order_by('id', 'toppings__order')
I am working with Django and Django REST framework. I have a model called Selection that contains field called category, when i query the model to send the result to the frontend i get it with the following structure:
[
{
"id": 1,
"category": "SHOES",
"products": 122,
"created_at": "2021-09-11",
},
{
"id": 2,
"category": "SHOES",
"products": 4,
"created_at": "2021-10-07",
},
{
"id": 3,
"category": "CLOTHES",
"products": 0,
"created_at": "2021-10-08",
},
]
I need to put the selections of the same category in an array and remove the grouped-by category, like this:
{
"SHOES": [
{
"id": 1,
"products": 122,
"created_at": "2021-09-11",
},
{
"id": 2,
"products": 4,
"created_at": "2021-10-07",
}
],
"CLOTHES": [
{
"id": 3,
"category": "CLOTHES",
"products": 0,
"created_at": "2021-10-08",
}
]
}
I considered to making it with Javascript in the frontend, but before i wanted to know if there's a way to do this from Django.
Yes, you need to do some customisation in your code.
Get all categories by using values_list('category', flat=True) with your queryset
Iterate through them filtering category one by one
response_list = []
categories = Selection.objects.values_list('category', flat=True)
for category in categories:
data = Selection.objects.filter(category=category)
data = {
category: SelectionSerializer(data, many=True).data,
}
response_list.append(data)
I have these 2 models:
class Question(models.Model):
title = models.CharField(max_length=200)
# other fields
class Answer(models.Model):
user = models.ForeignKey(User)
question = models.ForeignKey(Question)
score = models.IntegerField()
each user can answer a question multiple times.
Imagine I have these answers:
{
"user": 1,
"question": 1,
"score": 50
},
{
"user": 1,
"question": 1,
"score": 100
},
{
"user": 2,
"question": 1,
"score": 100
},
{
"user": 2,
"question": 1,
"score": 200
},
{
"user": 2,
"question": 2,
"score": 100
},
{
"user": 2,
"question": 2,
"score": 200
}
I want a query to give me this result:
{
"user": 1,
"question": 1,
"max_score": 100
},
{
"user": 2,
"question": 1,
"max_score": 200
},
{
"user": 2,
"question": 2,
"max_score": 200
}
I want all of the max scores of each user to each answer.
Try this:
from django.db.models import Max
Answer.objects.all().values("user", "question").annotate(score=Max("score"))
I'm not sure how to achieve your goal with Django ORM, but you can do it with RawSQL
Answer.objects.raw("""
select a1.* from answer a1 LEFT JOIN answer a2
ON (
a1.user_id = a2.user_id and a1.score < a2.score
)
where a2.user_id isnull
""")
Explanation: you get only records from you table, that have no bigger score from same table for each user.
I'm working on a simple blog system. Here is my models.py file:
from django.contrib.auth.models import User
from django.db import models
class Comment(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey('Post')
content = models.TextField()
approved = models.NullBooleanField()
class Meta:
ordering = ('-id',)
def __unicode__(self):
return u'Comment by %s' % self.user
class Post(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=200)
slug = models.CharField(max_length=50)
content = models.TextField()
class Meta:
ordering = ('title',)
def __unicode__(self):
return self.title
Here is some test data in a fixture which I've named testdata.json (the "some_author" user is a superuser and the password is "Stack Overflow"):
[
{
"pk": 1,
"model": "auth.user",
"fields": {
"username": "some_author",
"first_name": "Some",
"last_name": "Author",
"is_active": true,
"is_superuser": true,
"is_staff": true,
"last_login": "2014-07-02T20:18:49Z",
"groups": [],
"user_permissions": [],
"password": "pbkdf2_sha256$12000$PTl1hfgcIGZy$/0w1jNMBuKi9zk11JXhoS5WrbMBUgMDkZAhEvNEelbs=",
"email": "some_author#example.com",
"date_joined": "2014-07-02T20:18:29Z"
}
},
{
"pk": 2,
"model": "auth.user",
"fields": {
"username": "some_reader",
"first_name": "Some",
"last_name": "Reader",
"is_active": true,
"is_superuser": false,
"is_staff": false,
"last_login": "2014-07-02T20:21:10Z",
"groups": [],
"user_permissions": [],
"password": "pbkdf2_sha256$12000$CtTGfFeOaRhd$oVR6zFSpK2qg1AZ4fgdBG/wt6Sr56dHsEIxFO99mHC8=",
"email": "some_reader#example.com",
"date_joined": "2014-07-02T20:21:10Z"
}
},
{
"pk": 3,
"model": "auth.user",
"fields": {
"username": "another_reader",
"first_name": "Another",
"last_name": "Reader",
"is_active": true,
"is_superuser": false,
"is_staff": false,
"last_login": "2014-07-02T20:21:34Z",
"groups": [],
"user_permissions": [],
"password": "pbkdf2_sha256$12000$ZPnmV7fVeie3$08H2vv3A8Py4E92+uVAIiEaeg8CAL5deTyNAZj1YJMs=",
"email": "another_reader#example.com",
"date_joined": "2014-07-02T20:21:34Z"
}
},
{
"pk": 1,
"model": "blog.comment",
"fields": {
"content": "Comment 1 of 1 on post 1: approved",
"post": 1,
"user": 2,
"approved": true
}
},
{
"pk": 2,
"model": "blog.comment",
"fields": {
"content": "Comment 1 of 1 on post 2: not approved",
"post": 2,
"user": 2,
"approved": false
}
},
{
"pk": 3,
"model": "blog.comment",
"fields": {
"content": "Comment 1 of 2 on post 3: approved",
"post": 3,
"user": 2,
"approved": true
}
},
{
"pk": 4,
"model": "blog.comment",
"fields": {
"content": "Comment 2 of 2 on post 3: not approved",
"post": 3,
"user": 2,
"approved": false
}
},
{
"pk": 5,
"model": "blog.comment",
"fields": {
"content": "Comment 1 of 2 on post 4: not approved",
"post": 4,
"user": 2,
"approved": false
}
},
{
"pk": 6,
"model": "blog.comment",
"fields": {
"content": "Comment 2 of 2 on post 4: approved",
"post": 4,
"user": 2,
"approved": true
}
},
{
"pk": 7,
"model": "blog.comment",
"fields": {
"content": "Comment 1 of 2 on post 5: approved",
"post": 5,
"user": 2,
"approved": true
}
},
{
"pk": 8,
"model": "blog.comment",
"fields": {
"content": "Comment 2 of 2 on post 5: approved",
"post": 5,
"user": 2,
"approved": true
}
},
{
"pk": 9,
"model": "blog.comment",
"fields": {
"content": "Comment 1 of 2 on post 6: not approved",
"post": 6,
"user": 2,
"approved": false
}
},
{
"pk": 10,
"model": "blog.comment",
"fields": {
"content": "Comment 2 of 2 on post 6: not approved",
"post": 6,
"user": 2,
"approved": false
}
},
{
"pk": 11,
"model": "blog.comment",
"fields": {
"content": "Comment 1 of 1 on post 7: approved",
"post": 7,
"user": 3,
"approved": true
}
},
{
"pk": 1,
"model": "blog.post",
"fields": {
"content": "First post",
"slug": "post-1",
"user": 1,
"title": "Post 1"
}
},
{
"pk": 2,
"model": "blog.post",
"fields": {
"content": "Second post",
"slug": "post-2",
"user": 1,
"title": "Post 2"
}
},
{
"pk": 3,
"model": "blog.post",
"fields": {
"content": "Third post",
"slug": "post-3",
"user": 1,
"title": "Post 3"
}
},
{
"pk": 4,
"model": "blog.post",
"fields": {
"content": "Fourth post",
"slug": "post-4",
"user": 1,
"title": "Post 4"
}
},
{
"pk": 5,
"model": "blog.post",
"fields": {
"content": "Fifth post",
"slug": "post-5",
"user": 1,
"title": "Post 5"
}
},
{
"pk": 6,
"model": "blog.post",
"fields": {
"content": "Sixth post",
"slug": "post-6",
"user": 1,
"title": "Post 6"
}
},
{
"pk": 7,
"model": "blog.post",
"fields": {
"content": "Seventh post",
"slug": "post-7",
"user": 1,
"title": "Post 7"
}
},
{
"pk": 8,
"model": "blog.post",
"fields": {
"content": "Eighth post",
"slug": "post-8",
"user": 1,
"title": "Post 8"
}
}
]
I'm trying to query the database for all of the blog posts along with each blog post's most recent comment that meets both of these two conditions:
The comment was made by "Some Reader" (user_id = 2)
The comment has been approved
I want the query to return all of the blog posts, even if they don't have a comment that meets the above two conditions. For the blog posts that don't have a comment that meets the above two conditions, the returned comment column should just be NULL. I have this working with raw SQL:
for p in Post.objects.raw(
'''
SELECT blog_post.id,
blog_post.title,
blog_comment.content
FROM blog_post
LEFT OUTER JOIN (SELECT post_id,
MAX(id) AS latest
FROM blog_comment
WHERE user_id = 2
AND approved = 1
GROUP BY post_id) AS x
ON x.post_id = blog_post.id
LEFT OUTER JOIN blog_comment
ON blog_comment.post_id = x.post_id
AND blog_comment.id = x.latest
ORDER BY blog_post.id;
'''
):
print '%s: %s' % (
p.title,
p.content,
)
The above code outputs this (which is what I want):
Post 1: Comment 1 of 1 on post 1: approved
Post 2: None
Post 3: Comment 1 of 2 on post 3: approved
Post 4: Comment 2 of 2 on post 4: approved
Post 5: Comment 2 of 2 on post 5: approved
Post 6: None
Post 7: None
Post 8: None
My question is this: is it possible to (efficiently) do this same thing, but without resorting to raw SQL? I like to avoid raw queries whenever possible.
You can't do it without raw sql inside django orm paradigm.
But you can do it with two queries to db:
from django.db.models import Max
posts = Post.objects.annotate(Max('comment_set__id'))
comments_cache = Comment.objects.filter(id__in= posts.values('id', flat=True))
comments_dict = dict([(item.id, item) for item in comments_cache])
for item in posts:
print post, comments_dict[item.id]
I often make complex queries and still can't find better way than get all data I need with few queries inside cache-object and than group it as I need.
Please don't use code like:
#get_comment: return self.comment_set.filter(user=user, approved=True).latest('id')
for post in Post.objects.all():
print post.get_comment(request.user)
It will produce len(posts) sql-queries to database. It's bad practice.
You want all posts, but comments should be the one that matches specified criteria otherwise None. For that you can add a method/property inPost` model to get recent comment the way you wanted.
Don't think there is good way of doing this with ORM.
Add following method in your model,
class Post(models.Model):
...
#your code
def get_comment(self, user):
comment = None
try:
comment = self.comment_set.filter(user=user, approved=True).latest('id')
except Comment.DoesNotExist:
comment = None #no comment matching criteria
return comment
From you view or other code, you can do
for post in Post.objects.all():
print post.get_comment(request.user)
this is my model
class Nisit(models.Model):
and this
class Page(models.Model):
followingNisit = models.ManyToManyField(Nisit,blank=True)
this is my resource
class NisitResource(ModelResource):
page = fields.ToManyField('chula.api.PageResource','page_set',null=True)
class Meta:
queryset = Nisit.objects.all()
resource_name = 'nisit'
filtering = {
'page' : ALL_WITH_RELATIONS,
'id' : ALL,
}
class PageResource(ModelResource):
followingNisit = fields.ToManyField(NisitResource, 'followingNisit',null=True)
reporter = fields.ManyToManyField(ReporterResource,'reporter')
followers_count = fields.CharField(attribute='followers_count')
class Meta:
queryset = Page.objects.all()
resource_name = 'page'
authorization= Authorization()
filtering = {
'id':ALL,
'followingNisit': ALL_WITH_RELATIONS,
}
It's ok when I request -------127.0.0.1:8000/api/v2/page/?format=json&followingNisit__id=1
But In the opposite way ,when i request ---------127.0.0.1:8000/api/v2/nisit/?format=json&page__id=1, I will get this error
{"error_message": "Cannot resolve keyword 'page_set' into field. Choices are: displayName, facebook, faculty, friend, id, major, n_id, name, page, password, picture, reporter, year_in_school", "traceback": "Traceback (most recent call last):\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 202, in wrapper\n response = callback(request, *args, **kwargs)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 441, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 474, in dispatch\n response = method(request, **kwargs)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 1127, in get_list\n objects = self.obj_get_list(request=request, **self.remove_api_resource_names(kwargs))\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 1890, in obj_get_list\n base_object_list = self.apply_filters(request, applicable_filters)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 1862, in apply_filters\n return self.get_object_list(request).filter(**applicable_filters)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\query.py\", line 624, in filter\n return self._filter_or_exclude(False, *args, **kwargs)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\query.py\", line 642, in _filter_or_exclude\n clone.query.add_q(Q(*args, **kwargs))\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\sql\\query.py\", line 1250, in add_q\n can_reuse=used_aliases, force_having=force_having)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\sql\\query.py\", line 1122, in add_filter\n process_extras=process_extras)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\sql\\query.py\", line 1316, in setup_joins\n \"Choices are: %s\" % (name, \", \".join(names)))\n\nFieldError: Cannot resolve keyword 'page_set' into field. Choices are: displayName, facebook, faculty, friend, id, major, n_id, name, page, password, picture, reporter, year_in_school\n"}
I have also been struggling with the same FieldError thrown from setup_joins, and I think I just solved my issue. I was trying to filter through a Many-to-Many relationship, and could never get the "_set" in fields.ToManyField() to work. After debugging the TastyPie code in the error case and in a working simple filter, I realized it may be possible to bypass the need for the intermediary resource altogether.
Here is what worked for me, I hope it helps in your situation. Since I don't know your model setup, I'll make up a similar example.
First, the models:
### models.py ###
from django.db import models
class Ingredient(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
def __unicode__(self):
return '%s' % (self.name)
class RecipeIngredient(models.Model):
recipe = models.ForeignKey('Recipe')
ingredient = models.ForeignKey('Ingredient')
weight = models.IntegerField(null = True, blank = True)
def __unicode__(self):
return '%s: %s' % (self.recipe, self.ingredient)
class Recipe(models.Model):
title = models.CharField(max_length=100)
ingredients = models.ManyToManyField(Ingredient, through='RecipeIngredient')
def __unicode__(self):
return '%s' % (self.title)
And here are the ModelResources:
### api.py ###
from tastypie.resources import ModelResource, ALL, ALL_WITH_RELATIONS
from tastypie import fields
from some_app.models import Ingredient, Recipe
class IngredientResource(ModelResource):
class Meta:
queryset = Ingredient.objects.all()
resource_name = 'ingredient'
filtering = {
'name': ALL,
}
class RecipeResource(ModelResource):
ingredients = fields.ToManyField(
'some_app.api.IngredientResource',
'ingredients',
full=True)
class Meta:
queryset = Recipe.objects.all()
resource_name = 'recipe'
filtering = {
'title': ALL,
'ingredients': ALL_WITH_RELATIONS,
}
Notice I do not have a RecipeIngredientResource, I hook directly to the IngredientResource, which works because the Recipe model includes the ManyToManyField ingredients with the option through='RecipeIngredient'
An example URL to filter all recipes for a particular ingredient then looks like:
http://localhost:8000/api/recipes/recipe/?ingredients__name=blueberry
And, for completeness, here's a fixture for a Django app named 'some_app' to save time entering data for anyone wanting to implement this example:
[
{
"pk": 1,
"model": "some_app.ingredient",
"fields": {
"name": "apple",
"description": "a tempting fruit"
}
},
{
"pk": 2,
"model": "some_app.ingredient",
"fields": {
"name": "cherry",
"description": "a red fruit"
}
},
{
"pk": 3,
"model": "some_app.ingredient",
"fields": {
"name": "blueberry",
"description": "a blue fruit"
}
},
{
"pk": 4,
"model": "some_app.ingredient",
"fields": {
"name": "flour",
"description": "used for baking and stuff"
}
},
{
"pk": 5,
"model": "some_app.ingredient",
"fields": {
"name": "sugar",
"description": "makes stuff sweet"
}
},
{
"pk": 1,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 1,
"weight": 3,
"ingredient": 1
}
},
{
"pk": 2,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 1,
"weight": 2,
"ingredient": 4
}
},
{
"pk": 3,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 1,
"weight": 4,
"ingredient": 5
}
},
{
"pk": 4,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 2,
"weight": 8,
"ingredient": 2
}
},
{
"pk": 5,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 2,
"weight": 4,
"ingredient": 4
}
},
{
"pk": 6,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 2,
"weight": 6,
"ingredient": 5
}
},
{
"pk": 7,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 3,
"weight": 15,
"ingredient": 3
}
},
{
"pk": 8,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 3,
"weight": 5,
"ingredient": 4
}
},
{
"pk": 9,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 3,
"weight": 6,
"ingredient": 5
}
},
{
"pk": 1,
"model": "some_app.recipe",
"fields": {
"title": "Apple Pie"
}
},
{
"pk": 2,
"model": "some_app.recipe",
"fields": {
"title": "Cherry Pie"
}
},
{
"pk": 3,
"model": "some_app.recipe",
"fields": {
"title": "Blueberry Pie"
}
}
]
This is the thing, if django tastypie works very similar to django (as anyone could expect) you are using a bad keyword, in you case, It wouldn't be page_set, use just page instead and it will work.
I recommend to you using a plural in the field name
pages = fields.ToManyField('chula.api.PageResource','page_set',null=True)
so the forward relation is pages and the backward relation is page_set I cant remember which now. But anyway it will look nicer.