I have a comment Model, where a comment can be a root item or under another comment.
I'm using REST API to get the full tree.
Is it possible to limit its depth, so for example It will stop after 3 nodes from each root comment.
I want to add a "more" feature instead of show the whole tree at once.
`
class CommentSerializer(serializers.ModelSerializer):
leaf_nodes = serializers.SerializerMethodField()
class Meta:
model = Comment
fields = [
'id',
'body',
"leaf_nodes"
]
def get_leaf_nodes(self, obj):
return CommentSerializer(obj.get_children(), many=True).data
`
I tried looking at the documentation on GitHub but didn't find a solution.
I think that your problem is at DRF level. You should try to set depth parameter for your serializer. From the doc:
The depth option should be set to an integer value that indicates the
depth of relationships that should be traversed before reverting to a
flat representation.
https://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization
In the end I found out that I can use the obj.tn_level to check the depth level of the item.
I used two Serializers.
The first one is for the first round, where I limit the tn_level based on a const in settings.
The second Serializer, uses a parameter I pass via context from the view to the Serializer, containing the level of the last leaf on the display and via another const from settings I fetch more nodes.
This way I show part of the nodes and via pressing "more" I load a few nodes each time.
Related
I need to do some custom sorting on a Member model which looks like this (simplified):
class User():
username = models.CharField()
# ...
class Member():
user = models.ForeignKey(User) # not required
invite_email = models.EmailField()
# ...
I need to sort my queryset of Member in the following way:
Members that do not have a user set come last;
Sort by user username alphabetically (case insensitive), or invite_email if Member does not have a user.
I can do the appropriate sorting with django:
queryset.order_by(Lower('user__username').asc(nulls_last=True), 'invite_email')
I thought that I could override the order_by method to apply my custom ordering.
My problem comes with DRF cursor pagination. Reading from the doc, it seems like the ordering should be a string, or an unchanging value generally speaking. But when I use the Lower expression to order my queryset as needed, the ordering received in the cursor pagination class is an OrderBy object. Doing so, the paginate_queryset method is unusable.
I find it weird that you can't apply a custom filtering with the DRF pagination classes. Am I missing something?
Thanks in advance for any tips you might have!
You may use a different kind of Pagination for your project.
Why did you chose cursor pagination?
Details from the documentation:
https://www.django-rest-framework.org/api-guide/pagination/#cursorpagination
Cursor based pagination is more complex than other schemes. It also requires that the result set presents a fixed ordering, and does not allow the client to arbitrarily index into the result set. However it does provide the following benefits:
Provides a consistent pagination view. When used properly CursorPagination ensures that the client will never see the same item twice when paging through records, even when new items are being inserted by other clients during the pagination process.
Supports usage with very large datasets. With extremely large datasets pagination using offset-based pagination styles may become inefficient or unusable. Cursor based pagination schemes instead have fixed-time properties, and do not slow down as the dataset size increases.
Further, if check the implementation of the cursor pagination you'll see:
...
assert '__' not in ordering, (
'Cursor pagination does not support double underscore lookups '
'for orderings. Orderings should be an unchanging, unique or '
'nearly-unique field on the model, such as "-created" or "pk".'
)
...
assert isinstance(ordering, (six.string_types, list, tuple)), (
'Invalid ordering. Expected string or tuple, but got {type}'.format(
type=type(ordering).__name__
)
This implementation specifically disallows other order options than simple field based ordering using a string.
If you don't have any super large datasets, you probably wanna chose another pagination implementation like Page
Basically you can always create your own paginator class and overwrite paginate_queryset and add custom sorting.
I have a Feed model with the following field:
class Feed(models.Model)
authority=models.ForeignKey(Authority,blank=True,null=True)
I have a queryset of authority called followed_authority in which I want to get the corresponding feeds from each of the authority in followed_authority
The obvious thing for me is to use a for loop through followed_authority which I think its inefficient as the instanaces in following_authority and their corresponding feeds are very large.Kindly help me out
The correct thing to do is to always start from the model you want to get.
Feed.objects.filter(authority__in=followed_authority)
I am quite new to google app engine. I know google datastore is not sql, but I am trying to get many to many relationship behaviour in it. As you can see below, I have Gif entities and Tag entities. I want my application to search Gif entities by related tag. Here is what I have done;
class Gif(ndb.Model):
author = ndb.UserProperty()
link = ndb.StringProperty(indexed=False)
class Tag(ndb.Model):
name = ndb.StringProperty()
class TagGifPair(ndb.Model):
tag_id = ndb.IntegerProperty()
gif_id = ndb.IntegerProperty()
#classmethod
def search_gif_by_tag(cls, tag_name)
query = cls.query(name=tag_name)
# I am stuck here ...
Is this a correct start to do this? If so, how can I finish it. If not, how to do it?
You can use repeated properties https://developers.google.com/appengine/docs/python/ndb/properties#repeated the sample in the link uses tags with entity as sample but for your exact use case will be like:
class Gif(ndb.Model):
author = ndb.UserProperty()
link = ndb.StringProperty(indexed=False)
# you store array of tag keys here you can also just make this
# StringProperty(repeated=True)
tag = ndb.KeyProperty(repeated=True)
#classmethod
def get_by_tag(cls, tag_name):
# a query to a repeated property works the same as if it was a single value
return cls.query(cls.tag == ndb.Key(Tag, tag_name)).fetch()
# we will put the tag_name as its key.id()
# you only really need this if you wanna keep records of your tags
# you can simply keep the tags as string too
class Tag(ndb.Model):
gif_count = ndb.IntegerProperty(indexed=False)
Maybe you want to use list? I would do something like this if you only need to search gif by tags. I'm using db since I'm not familiar with ndb.
class Gif(db.Model):
author = db.UserProperty()
link = db.StringProperty(indexed=False)
tags = db.StringListProperty(indexed=True)
Query like this
Gif.all().filter('tags =', tag).fetch(1000)
There's different ways of doing many-to-many relationships. Using ListProperties is one way. The limitation to keep in mind if using ListProperties is that there's a limit to the number of indexes per entity, and a limit to the total entity size. This means that there's a limit to the number of entities in the list (depending on whether you hit the index count or entity size first). See the bottom of this page: https://developers.google.com/appengine/docs/python/datastore/overview
If you believe the number of references will work within this limit, this is a good way to go. Considering that you're not going to have thousands of admins for a Page, this is probably the right way.
The other way is to have an intermediate entity that has reference properties to both sides of your many-to-many. This method will let you scale much higher, but because of all the extra entity writes and reads, this is much more expensive.
I have a Chart model that consist of multiple Box models (so Box has a foreign key to Chart). The Box models have a field number that defines their order inside the Chart.
Now Box will have a method that returns it's contents. What the contents is, depends on the properties of the previous box and the next one (if there are any). So from the Box model I need to have a reference to the preceding Box and the upcomming Box.
Now I see two options:
Make foreign keys for the previous and next Box.
Ask Chart for a box where number = (current box number -1 or +1)
What would be the most efficitent way to do this and why? If I use the foreignkey method, will it do extra queries or does it make this connections automatically? Of course I must use select_related on the queryset to get the complete Chart. And what option do you think is most scalable?
I know I can test this of course but I wonder what other people might think of this and if there are other solutions to this that I didn't realize.
A possible solution is the following method in the Box model:
def get_ordering(self):
try:
top = Box.models.filter(number__lt=self.number).order_by('-number')[0]
except IndexError:
top = None
try:
bottom = Box.models.filter(number__gt=self.number).order_by('number')[0]
except IndexError:
top = None
return top,bottom
However, a better solution would be to use django-mptt an implementation of tree traversal for django.
I have the following problem:
I have two models: Article and Comment, in Comments, i have parent = models.ForeignKey(Article). I have it set up so that Comments is inline to ArticleAdmin(admin.ModelAdmin), and CommentInline(admin.StackedInline). What i would like is that for Article list view (elements chosen in list_display), I would like to display snippets of latest comments so that the user does not have to click into each individual comments to see the changes. Now i know that i can specify a function in list_display, but i'm not sure how to do what i wish to do easily in the functions.
anyone have any suggestion on how to go about accomplishing this?
Thank you very much for your help!
As you say, defining a function is the way to go - a custom method on the ModelAdmin class which takes the object as a parameter and returns a string representation of the latest comments:
class ArticleAdmin(admin.ModelAdmin):
list_display = ('name', 'latest_comments')
def latest_comments(self, obj):
return '<br/>'.join(c.comment for c in obj.comment_set.order_by('-date')[:3])
latest_comments.allow_tags = True
This takes the last three comments on each article, sorted by the 'date' field, and displays the comment field of each one, separated by an HTML <br> tag to show on one each line.