Django: limit queryset to a condition in the latest instance of a related set - django

I have an hierarchy of models that consists of four levels, all for various good reasons but which to explain would be beyond the scope of this question, I assume.
So here it goes in pseudo python:
class Base(models.Model):
...
class Top(models.Model):
base = FK(Base)
class Middle(models.Model):
top = FK(Top)
created_at = DateTime(...)
flag = BooleanField(...)
class Bottom(models.Model):
middle = FK(Middle)
stored_at = DateTime(...)
title = CharField(...)
Given a title, how do I efficiently find all instances of Base for which that title is met only in the latest (stored_at) Bottom instance of the latest (created_at) Middle instance that has flag set to True?
I couldn't find a way using the ORM, and the way I've seen it, .latest() isn't useful to me on the model that I want to query. The same holds for any convenience methods on the Base model. As I'm no SQL expert, I'd like to make use of the ORM as well as avoid denormalization as much as possible.
Thanks!

So, apparently, without heavily dropping into (some very unwieldy) SQL and not finding any alternative solution, I saw myself forced to resort to denormalized fields on the Base model, just as many as were required for efficiently getting the wanted (filtered) querysets of said model.
These fields were then updated at creation/modificatin time of respective Bottom instances.

Related

Ordering models using Django AutoField with custom step size

Consider a model Section that is displayed on a site and created / edited by a user using the Django admin interface. I would like to add a field that allows the user to easily control the order in which sections are displayed on the site. The easiest option seems to be to allow for an integer field that is auto-incremented but can be edited by the user -- akin to what the built-in AutoField does.
However, to make editing the order easier, I would like to increment the fields default value by 10 every time, to allow the user to shift sections around more easily. The first section would get order=1, the next one order=11 and so on, that way a section can be wedged in between those first two by giving it, e.g., order=6.
Is there a way I can reuse AutoField to achieve this purpose? And if no, how could I best achieve this type of ordering scheme?
Ideally, what I'd like to achieve should look like this:
from django.db import models
class Section(models.Model):
text = models.TextField()
order = AutoField(step=10)
class Meta:
ordering = ('order',)
Autofield won't work. Not editable, needs to be primary key.
I also suggest to solve this visually using drag and drop in the UI and then reorder all sections within the whole, rather then allow wedging. If two people at the same time wedge 25 within 20 and 30, you still have the same problem. Reordering on save is a much cleaner solution, especially when using select_for_update:
Returns a queryset that will lock rows until the end of the transaction, generating a SELECT ... FOR UPDATE SQL statement on supported databases.

Why Many to Many relationship with self can't be symmetrical

I'm trying to make a model with many to many relationship to itself and this relationship will also have a specific table that will store some information about the relationship, but I'm running into some problems.
I tried to make a many to many relationship with diferent models like the Django docs say, and it's worked fine in some other point of my application. But now I tried to do something like this:
Let's say that I want a model that represents an object (called Item) that is made by other items and also is used to make some other items. For instance, an object Door is made by wood and lock, but Door will also be used to make a House. I thought in something like this for my models
class Item(models.Model):
name = models.CharField(max_length=100)
items = models.ManyToManyField("self",through='IsMadeBy')
class IsMadeBy(models.Model):
itemResult = models.ForeignKey('Item', related_name='itemResult')
itemPart = models.ForeignKey('Item', related_name='itemPart')
amountUsed = models.PositiveIntegerField()
I'm getting the error message:
Many-to-many fields with intermediate tables must not be symmetrical.
So, adding the argument
symmetrical=False
to my relationship the error stops.
With that being said, I want to know how this really works under the hood. For intance, what the symmetrical means in this context in a database level? I would appreciate if anyone could give examples maybe using SQL statements, since right now my brain can't see the overall situation and really learn this concept of symmetrical relationship in a many to many relationship with self.
Look at the Django docs:
https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ManyToManyField.symmetrical
With symmetric relationship if i'm your friend then you my friend too - in Django terms, you have one relation.
With non-symmetric direct and reverse relations can be different, you have related_set. For example, if i'm you manager, you not my manager at the same time, but manager via employee_set can have many employees.

Is it mandatory to specify intermediate model to describe 'level' of many-to-many relationship?

Being new to Django and relatively new to python, I am writing a knowledge reporting webpage.
I have 2 models with a defined MtM relationship:
Class Student:
level_of_knowledge = model.ManyToMany(Topic)
...
Class Topic:
...
Intended usage:
Every Student has a level of understanding of every topic (the list of topics is exactly the same for everyone), starting with, say, "Basic". The level of understanding may be increased to "Intermediate" and further to "Advanced".
Question:
Is it necessary to implement an intermediate "through" model with the determined list of levels of undestanding, or can it be done in the level_of_knowledge field in Student model directly?
Personally, I would create an intermediate model in this case, but if you want more ideas of what you could do then something like this would work too:
Class Student:
advanced_knowledge = model.ManyToMany(Topic)
intermediate_knowledge = model.ManyToMany(Topic)
basic_knowledge = model.ManyToMany(Topic)
...
Class Topic:
...
So this is neat because you can easily access knowledge of a certain level by using student.basic_knowledge.all()
But here's the problem:
What if you want a list of all Topic objects related to a Student? Do you combine all three of these queries?
What if you want to add a few more knowledge levels? Maybe later students will have beginner knowledge or expert knowledge. How many other ManyToMany fields will you end up adding?
Using an intermediate model solves both of these problems, and its not hard to use the django through option and filter by levels if you want. Just make properties or methods on Student for the knowledge levels you filter by most often.
Class Student:
level_of_knowledge = model.ManyToMany(Topic, through=MyIntermediteModel)
def advanced_knowledge(self):
return self.level_of_knowledge.filter(...) # filter by intermedite model where level = 'advanced'

Do Django models really need a single unique key field

Some of my models are only unique in a combination of keys. I don't want to use an auto-numbering id as the identifier as subsets of the data will be exported to other systems (such as spreadsheets), modified and then used to update the master database.
Here's an example:
class Statement(models.Model):
supplier = models.ForeignKey(Supplier)
total = models.DecimalField("statement total", max_digits=10, decimal_places=2)
statement_date = models.DateField("statement date")
....
class Invoice(models.Model):
supplier = models.ForeignKey(Supplier)
amount = models.DecimalField("invoice total", max_digits=10, decimal_places=2)
invoice_date = models.DateField("date of invoice")
statement = models.ForeignKey(Statement, blank=True, null=True)
....
Invoice records are only unique for a combination of supplier, amount and invoice_date
I'm wondering if I should create a slug for Invoice based on supplier, amount and invoice_date so that it is easy to identify the correct record.
An example of the problem of having multiple related fields to identify the right record is django-csvimport which assumes there is only one related field and will not discriminate on two when building the foreign key links.
Yet the slug seems a clumsy option and needs some kind of management to rebuild the slugs after adding records in bulk.
I'm thinking this must be a common problem and maybe there's a best practice design pattern out there somewhere.
I am using PostgreSQL in case anyone has a database solution. Although I'd prefer to avoid that if possible, I can see that it might be the way to build my slug if that's the way to go, perhaps with trigger functions. That just feels a bit like hidden functionality though, and may cause a headache for setting up on a different server.
UPDATE - after reading initial replies
My application requires that data may be exported, modified remotely, and merged back into the master database after review and approval. Hidden autonumber keys don't easily survive that consistently. The relation invoices[2417] is part of statements[265] is not persistent if the statement table was emptied and reloaded from a CSV.
If I use the numeric autonumber pk then any process that is updating the database would need to refresh the related key numbers or by using the multiple WITH clause.
If I create a slug that is based on my 3 keys but easy to reproduce then I can use it as the key - albeit clumsily. I'm thinking of a slug along the lines:
u'%s %s %s' % (self.supplier,
self.statement_date.strftime("%Y-%m-%d"),
self.total)
This seems quite clumsy and not very DRY as I expect I may have to recreate the slug elsewhere duplicating the algorithm (maybe in an Excel formula, or an Access query)
I thought there must be a better way I'm missing but it looks like yuvi's reply means there should be, and there will be, but not yet :-(
What you're talking about it a multi-column primary key, otherwise known as "composite" or "compound" keys. Support in django for composite keys today is still in the works, you can read about it here:
Currently Django models only support a single column in this set,
denying many designs where the natural primary key of a table is
multiple columns [...] Current state is that the issue is
accepted/assigned and being worked on [...]
The link also mentions a partial implementation which is django-compositekeys. It's only partial and will cause you trouble with navigating between relationships:
support for composite keys is missing in ForeignKey and
RelatedManager. As a consequence, it isn't possible to navigate
relationships from models that have a composite primary key.
So currently it isn't entirely supported, but will be in the future. Regarding your own project, you can make of that what you will, though my own suggestion is to stick with the fully supported default of a hidden auto-incremented field that you don't even need to think about (and use unique_together to enforce the uniqness of the described fields instead of making them your primary keys).
I hope this helps!
No.
Model needs to have one field that is primary_key = True. By default this is the (hidden) autofield which stores object Id. But you can set primary_key to True at any other field.
I've done this in cases, Where i'm creating django project upon tables which were previously created manually or through some other frameworks/systems.
In reality - you can use whatever means you can think of, for joining objects together in queries. As long as query returns bunch of data that can be associated with models you have - it does not really matter which field you are using for joins. Just keep in mind, that the solution you use should be as effective as possible.
Alan

How to fetch and display data from 2 models in a single queryset ordered by time, Django

I want to have facebook kind of news feed, in which i need to fetch data from 2 different models ordered by time.
Models are something like :
class User_image(models.Model):
user = models.ForeignKey(User_info)
profile_pic = models.ImageField(upload_to='user_images')
created = models.DateTimeField(auto_now_add=True)
class User_status(models.Model):
user = models.ForeignKey(User_info)
status = models.CharField(max_length=1)
created = models.DateTimeField(auto_now_add=True)
As per my requirement, i can not make a single model out of these two models.
Now i need to know the simple code in views and template so as to display profile pic and status in the news feed according to time.
Thanks.
The most simple way of archiving this is to have a base model, call it Base_event,
class Base_event(models.Model):
user = models.ForeignKey(User_info)
created = models.DateTimeField(auto_now_add=True)
and derive both your models from this Base. This way you write less code, and you archive your objective. Notice that you have to make an implementation choice: how will they will inherit from base. I advice to read Django documentation to help you choose wisely according to what you want to do.
EDIT:
I would notice that the accepted answer has a caveat. It sorts the data on the python and not on the mysql, which means it will have an impact on the performance: the whole idea of mysql having SORT is to avoid having to hit the database and them perform the sorting. For instance, if you want to retrieve just the first 10 elements sorted, with the accepted solution you have to extract all the entries, and only then decide which ones are the first 10.
Something like Base_event.objects.filter().sort_by(...)[10] would only extract 10 elements of the database, instead of the whole filtered table.
The easy solution now becomes the problem later.
Try something like creating list chain.
feed = list(chain(User_image,User_status))
feed = sorted(feed, key=operator.attrgetter('date_added'))
for those who refer it as not correct.
https://stackoverflow.com/a/434755/2301434