Resource nesting with tastypie - python

Trying to do something pretty simple with tastypie, but cannot figure out how. Lets say I have a model Author and a mode Book with a foreign key pointing to author. And I have an Author resource. So, /api/v1/author would get me a list of authors and /api/v1/author/1 would get me details on a particular author. I want /api/v1/author/1/books to get me a list of books for this particular author. How?
Example code:
from django.db import models
from tastypie.resource import ModelResource
class Author(models.Model):
name = models.CharField(max_length=200)
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey('Author')
class AuthorResource(ModelResource):
queryset = Author.objects.all()

Looks like the recipe for this was actually in the cookbook, but for something so obvious, the implementation is rather awkward.
http://django-tastypie.readthedocs.org/en/latest/cookbook.html#nested-resources

Related

Is it possible to use a related field as a choice field in Django?

In Django, if I have something like this:
class Library(models.Model):
name = models.CharField(...)
address = models.CharField(...)
book_of_the_week = ?
class Book(models.Model):
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name="books")
name = models.CharField(...)
This gives me the ability to create multiple libraries, each with a large number of books.
For book_of_the_week, I want this to be a reference to a Book instance, so that in Django Admin, the field is represented as a dropdown that lets you select from the books in the current library, and in code, you can use .book_of_the_week to access a specific instance of Book.
Is this possible?
Sure, it's possible. But if you do this, you'll only ever be able to save the current book of the week. What happens if you want to show a library's book-of-the-week history? Seems like a likely scenario to me. Consider doing something like:
class Library(models.Model):
name = models.CharField(...)
address = models.CharField(...)
book_of_the_week = ?
class Book(models.Model):
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name="books")
name = models.CharField(...)
class BookOfTheWeek(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='book_of_the_week')
library = models.ForeignKey(Library, ...etc)
week_of = models.DateField()
In this manner every book of the week will be a discrete database record, and you'll be able to track a history of each library's book of the week over time.
However...
That said, if you do not need to do this and a single instance record is fine, you should be able to create a ForeignKey relation from Library to Book. However, you may run into some circular and/or hierarchical reference issues depending on how where your model classes are written. In the example you show above, you'd need to declare your ForeignKey model name as a string, like so:
book_of_the_week = models.ForeignKey('Book', on_delete ... etc)
instead of:
book_of_the_week = models.ForeignKey(Book, on_delete ... etc)
...otherwise Django will throw an error because the Book model class is referenced before it is defined. Making 'Book' a string will let Django parse the full models.py file, build the logic, and avoid the error.
Sidenote:
Depending on your specific case you may also consider a ForeignKey to self, like so:
class Book(models.Model):
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name="books")
name = models.CharField(...)
book_of_the_week = models.ForeignKey('self', on_delete=models.SET_NULL, ...etc)
This would allow any Book on the database table to reference another single Book instance.

Error when adding many-to-many-field on Post

I have an app within my project called posts, where inside their in the models.py, I have two models: Post and Like.
I want to add a many-to-many-field on the post that references the Like model.
I have executed makemigrations and migrate, however I am getting this error:
NameError: name 'Like' is not defined
models.py:
class Post(models.Model):
file = models.ImageField(upload_to='images/')
summary = models.TextField(max_length=600)
pub_date = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(Like)
def __str__(self):
return self.user.username
def summary_pretty(self):
return self.summary[:50]
def pub_date_pretty(self):
return self.pub_date.strftime('%b %e %Y')
class Like(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=False)
it says
NameError: name 'Like' is not defined
because you must move Like model above Post model it hasn't been defined yet in your code in that line (python code is interpreted)
and it's not a good thing to design database models like that based on:
Why should I avoid loops when designing relationships for a database?
so delete the Post foreign key in Like model and you can retrieve a like's post with reverse lookup
you can find more about it in django official docs:
Lookups that span relationships
and also
Many-to-many relationships
You're referencing the class Like before initiating it in your Python file. Hence "Like" is not defined.
likes = models.ManyToManyField(Like)
You need to delete "likes" from your Post class. That will fix the error.
As for your code, I think you're misunderstanding why we use Intermediary Tables. You don't need to reference Like in your Post class. You've already established that relationship in the Like Class:
post = models.ForeignKey(Post, on_delete=models.CASCADE)
Retrieving the users who have liked a post is as simple as writing a filter on the Likes table.
#views.py
from models import Post, Like
post_id = 1
likes = Like.objects.filter(post=post_id)

Django Aggregate ManyToMany fields

Say I have Django models like so:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
authors = models.ManyToManyField(Author)
What's the best way to get the the number of books each author created (preferably ordered) within a query or two?
The Author set might get pretty big, so I'm looking for a way to avoid iterating over all of it.
in your model book add...
...
author = models.ForeignKey(Author)
...
and to get then you use a QuerySet like
...
Author.objects.get(id=some_id).book_set.all() # this line, return all book of these author, if you want get the number just add at end '.count()'
...

Django multiple tag field

I'm trying to find a good tutorial for django how to create multiple tags in a model.
For example:
class Tag(models.Model):
name = models.CharField()
class Sample(models.Model):
name = models.CharField()
urlA = models.CharField()
urlB = models.CharField()
tagA = models.ManyToManyField(Tag)
tagB = models.ManyToManyField(Tag)
I would like to display the tags as an input field and separate by ',' and split in the save method. So I'd like to see 2 different input for the 2 tag field.
If you have an easy way to do or know a good tutorial, please tell me! :)
Thank you guys!
Edit: you do not have to have the actual table sets over laid. You can generate any queryset you want to inn your views. Your url conf can be set up to display the detail view from multiple url. If i am still not understanding then please refine your question.
For having multiple anything tags categories your either going m21 or m2m. So when you create your tags you can add them one by one. Are you familiar with what the Django ORM has to offer with some of its admin functionality? Please give the documentation a good look through. Your approach to this problem is anything but reasonable. Not trying to rub you the wrong way I'm no genius. You would do something like so.
class Tag(models.Model):
title = models.CharField(max_length=250, blank=True)
slug = models.SlugField(blank=True
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
ordering = ['title']
#models.permalink
def get_absolute_url(self):
return "/tags/%s/" % self.slug
class Entry(models.Model):
title = models.CharField(max_length=250, blank=True)
body = models.TextField()
tags = models.ManyToMany('Tag')
slug = models.SlugField()
#models.permalink
def get_absolute_url(self):
return "/blog/%s/" % self.slug
There's a little more code to be done for the EntryAdmin and the TagAdmin models, Many other things that can be done as well. I am not sure what you are trying to achieve with that if you could be more clear? Thank you, the above is a rough illustration of how I would approach it.
I found a solution from here:
https://dev.to/thepylot/how-to-add-tags-to-your-models-in-django-django-packages-series-1-3704
django-taggit is very useful for tagging.
It is
a reusable application that primarily offers you a Tag model, and a manager for easily adding tags to any model.
pip install django-taggit
After that, open settings.py and edit the installed apps section:
INSTALLED_APPS = [
...
'taggit'
]
After that, edit your model and add tags like this:
tags = TaggableManager()
The TaggableManager will show up automatically as a field in a ModelForm or in the admin.
Documentation: https://django-taggit.readthedocs.io/en/latest/index.html

Select Children of an Object With ForeignKey in Django?

I'm brand new to Django, so the answer to this is probably very simple. However, I can't figure it out.
Say I have two bare-bones Models.
class Blog(models.Model):
title = models.CharField(max_length=160)
text = models.TextField()
class Comment(models.Model):
blog = models.ForeignKey(Blog)
text = models.TextField()
In the Python/Django shell, if I have a Blog object in a variable (say blog = Blog.objects.get(id=3)), how do I select all its child comments?
This doesn't seem to work: blog.objects.all()
to follow foreign keys 'backwards' you use
blog.comment_set.all()

Categories