Getting objects.all() reverse() or descending order - django

In Django, calling object.manytomany.all().reverse(), and its template equivalent, object.manytomany.all.reverse, don't seem to work for many-to-many relationships.
How do I reverse a list of results of a many-to-many relationship?

You may be going about this wrong or maybe I misunderstand your code snippet. Say you have a Book Model where an instance of a Book can have multiple authors.
class Author(models.Model):
...
class Book(models.Model):
authors = models.ManyToManyField(Author)
Now this will return a QuerySet of all Book instances - Book.objects.all()
objects is the default manager for a Model and it's plural. object is its own thing in Python and it's best not to use it as your own variable. It's also worth stating that "manytomany" isn't a field or function in Django. Let us know if that's something you defined. So to get the ManyToMany multiple authors a book instance might have:
book = Book.objects.all()[0]
type(book.authors) # tells you this is a ManyRelatedManager
type(book.authors.all()) # tells you this is a QuerySet
book.authors.all() # will print out the authors for this book
Now that you have the authors and those authors are in the form of a QuerySet, you can do any normal QuerySet manipulation including reversing.
book.authors.all().reverse()
Remember that reversing something that isn't ordered doesn't mean much so you may want to consider using objects.order_by("<field name>").reverse(). Hope that helps.

So you can do it as
object.manytomany.order_by("-id")

This can be used to order objects in the order we want according to their properties.
Doubt.objects.all().order_by('-date_posted')

book = reversed(Book.objects.all())

Related

django iterate through model objects that contain another particular model object in a ManyToManyField

I have the following models in my django app.
class author(models.Model):
name=models.CharField(max_length=100)
class book(models.Model):
name=models.TextField()
authors=models.ManyToManyField(author)
A author definately have written multiple books. A single book can also have multiple authors.
I want to iterate through all books by a particular author. Till now I have tried
for b in book.objects.filter(authors__name='HiDe'):
print(b)
which gives AttributeError: 'function' object has no attribute 'objects' probably because authors in book is a ManyToManyField.
Adding books=models.ManyToManyField(author) will make the database large and cumbersome to manage as an author can have too many books, so this is not the solution I want.
How do you define the book?
It seems it is just a function. Not a model object.
The error tells you books doesn't have the attribute objects, and is a function.
It is also generally good practice to capitalise the first letter of Django models.

Repeated fields in django models

I need to make a model that has 15 similar fields (let's call them field_01, field_02, field_03, etc.). I also need these fields to be easily available (e.g. to be able to do things like obj.field_01). Because I wanted to get something off the ground really quickly, I just created them the stupid way:
class M (models.Model):
....
field_01 = models.NullBooleanField()
field_02 = models.NullBooleanField()
....
I searched online for a better way to do this. Some people say use setattr, but as far as I could tell from reading and trying some stuff out, this adds attributes to an instance of a class, not the class itself, which means that when I try to attach a model form to this model, it will not see the fields added with setattr. Then I tried overriding the __new__ function, which would allow me to add properties to a class before an instance of that class is created. But I wasn't able to figure out how to do this exactly.
So, what's a way to generate these fields without breaking South and model forms and without copy-paste?
It's hard to say definitively without a concrete example of what your doing, but generally, if you find yourself repeating a field, then it's a clear sign for a one-to-many or many-to-many relationship, instead:
One-to-Many
class Field(models.Model):
m = models.ForeignKey(M, related_name='fields')
field = models.NullBooleanField()
Many-to-Many
class Field(models.Model):
field = models.NullBooleanField()
class M(models.Model):
fields = models.ManyToManyField(Field)
Django models have an add_to_class method you could (ab)use for monkey-patching models the way you would like to do.
for i in range(1, 10):
M.add_to_class('field_%s' % s, NullBooleanField())
It sounds like you are looking to have an EAV style database. You should try a library instead of rolling your own. To that end, Django EAV looks pretty awesome. https://github.com/mvpdev/django-eav
To read more about pros and cons of a bunch of libraries to accomplish this check out: https://stackoverflow.com/a/7934577/884453

Filter on prefetch_related in Django

Is there a way of filtering prefetched objects? I need to get the latest() of the prefetched objects but prefetch_related doesn't work if you use latest because the query is changed?
The example here does what I need but I was hoping there's a simpler workaround...
https://github.com/ionelmc/django-prefetch#example
As of Django 1.7, filtering prefetched objects is possible. See this SO answer, and the Django documentation.
It is very simple method which is hardly comparable with those app, but hope you will find it useful:
class Author(models.Model):
name = models.CharField(max_length=100)
def latest_book(self):
return max(self.book_set.all(), key=lambda book: book.created)
authors = Author.objects.prefetch_related('book_set')
authors[0].latest_book() # what you wanted
Yes, it can be done in this way :
authors=Author.objects.prefetch_related('book_set')
If you want to filter by an attribute(name) present in Author model you can simply filter it by writing:
authors.filter(name='your_value')
But if you want to apply filter on the Books model you have to write the following way:
authors.filter(book__created__gt='your_date')
This will filter all the books that have create date(created attribute in the Book module) greater than your date.

Making a fairly complex Django model method sortable in admin?

I have a reasonably complex custom Django model method. It's visible in the admin interface, and I would now like to make it sortable in the admin interface too.
I've added admin_order_field as recommended in this previous question, but I don't fully understand what else I need to do.
class Book(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=200)
library_id = models.CharField(max_length=200, unique=True)
def current_owner(self):
latest_transaction = Transaction.objects.filter(book=self)[:1]
if latest_transaction:
if latest_transaction[0].transaction_type==0:
return latest_transaction[0].user.windows_id
return None
current_owner.admin_order_field = 'current_owner'
Currently, when I click on the current_owner field in the admin interface, Django gives me
FieldError at /admin/books/book/
Cannot resolve keyword 'current_owner' into field
Do I need to make a BookManager too? If so, what code should I use? This isn't a simple Count like the example in the previous question, so help would be appreciated :)
Thanks!
The Django admin won't order models by the result of a method or any other property that isn't a model field (i.e. a database column). The ordering must be done in the database query, to keep things simple and efficient.
The purpose of admin_order_field is to equate the ordering of a non-field property to the ordering of something that is a field.
For example, a valid values current_owner.admin_order_field could be id, title or library_id. Obviously none of these makes sense for your purpose.
One solution would be to denormalise and always store current_owner as a model field on Book; this could be done automatically using a signal.
You can't do this. admin_order_field has to be a field, not a method - it's meant for when you have a method that returns a custom representation of an underlying field, not when you do dynamic calculations to provide the value. Django's admin uses the ORM for sorting, and that can't sort on custom methods.

Django model naming convention

What is the preferred naming convention for Django model classes?
Django models are just Python classes, so the Python naming conventions detailed in PEP-8 apply.
For example:
Person
Category
ZipCode
If Django fails to pluralize the class name properly when creating the corresponding table, you can easily override the pluralization by setting a custom verbose_name_plural field in an inner META class. For example:
class Story(models.Model):
...
class Meta:
verbose_name_plural = "stories"
As far as I know, the idea is that the class name should be singular and should use SentenceCase with no spaces. So you'd have names like:
Person
TelephoneNumber
Then the Django admin tool knows how to pluralise them. Doesn't work so nicely for names like:
Category
which gets pluralised as Categorys, but there we go...
Apart from that, just give it a name that means something to you and succinctly sums up what the class is meant to represent.
Ben
In most of programming languages, people prefer give a singular names to the objects/models because these models are also represented by tables in your database system. The minimalism is a good choice everytime to avoid some meaning conflicts in the future.
To exemplify;
https://stackoverflow.com/a/5841297/2643226
In adition, when you need related objects for a Model of more than one word, you can use the _set attribute. Example:
class ProcessRoom(models.Model):
...
plant = models.ForeignKey("Plant", verbose_name='planta', on_delete=models.CASCADE)
Then, related objects will be:
plant = Plant.object.get(id=1)
process_rooms = plant.processroom_set.all