Ordering by a OneToOne self-referencing field in Django - django

I'm trying to order a query by a self-referencing OneToOne field. The model:
class Foo(models.Model):
prior_foo = models.OneToOneField('self', related_name='following_foo', null=True, blank=True)
There is no guarantee that the pk for the linked item is higher or lower, (or any other field is useful besides the OneToOne reference) e.g.:
Foo.pk | prior_foo.pk
3 | null
6 | 3
5 | 6
10 | 5
I'd love to have the query return:
[foo_3, foo_6, foo_5, foo_10]

Related

Why would someone set primary_key=True on an One to one reationship (OneToOneField)?

I was watching a video on django-orm and the instructor stated that:
We should set primary_key=True to prevent a Model from having duplicate rows in a OneToOne relationship (Ex: Prevent a user from having multiple profiles).
I know this statement is wrong! AFAIK, an OneToOne field is just a ForeignKey with unique parameter set to True. But I got curious and looked-up the Django documentation, Sure enough they are using primary=True in their example.
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
So, why would someone set primary_key=True on an OneToOne relation?
My guess is that it's just reasonable to have that field as a primary key and there is no technical background behind it.
This is a pattern to implement object-oriented inheritance in a relational database, for example as this article of Oracle discusses.
Indeed, it means that one can define a Place, and for that Place create a Restaurant model as well. It has a OneToOneField(…) to the "parent" model. The OneToOneField prevents that one can define two (or more) Restaurants for the same Place.
Usually it is defined as a primary key, since then it shares the same "primary code space", and it removes a column that is otherwise used to do the mapping and thus would make the database larger.
Django will implement this the same way. If we define this as:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
pass
then it will be implemented as:
mysql> describe place;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | NULL | |
| address | varchar(80) | NO | | NULL | |
+---------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> describe restaurant;
+--------------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------+------+-----+---------+-------+
| place_ptr_id | int | NO | PRI | NULL | |
+--------------+------+------+-----+---------+-------+
It thus will add a primary key named place_ptr_id that refers to the place table. This originates from a OneToOneField that Django adds to the Restaurant model named place_ptr.
We should set primary_key=True to prevent a Model from having duplicate rows in a OneToOne relationship (Ex: Prevent a user from having multiple profiles)
This makes no sense, since a OneToOneField is in essence a ForeignKey with unique=True [Django-doc]. So this is already enforced by the OneToOneField, it is not necessary to make it a primary key.
Something that can not be done with the above modeling is preventing that an Place is a Restaurant and Library at the same time.

Django reading data from 2 models with foreignkey and make single list

I'm new to django. I've been coding with sql but django orm is hard for me to convert my knowledge of sql to orm models.
I've client model
class client(models.Model):
c_id = models.AutoField(primary_key=True)
name= models.TextField()
age=models.IntegerField()
and address model
class address(models.Model):
c_id = models.ForeignKey(client, on_delete=models.CASCADE)
addr = models.CharField(max_lenght=20)
city= models.CharField(max_lenght=20)
This is my table
---------------------------
| c_id|Name | age |
---------------------------
| 1 | John | 23 |
----------------------------
| 2 | Rose | 20 |
----------------------------
------------------------------
| c_id|addr | city |
------------------------------
| 1 | buspark | florida|
------------------------------
| 2 | homesquare| florida|
------------------------------
how to get allclient with address in list
Look at values() docs
The values() method takes optional positional arguments, *fields,
which specify field names to which the SELECT should be limited. If
you specify the fields, each dictionary will contain only the field
keys/values for the fields you specify. If you don’t specify the
fields, each dictionary will contain a key and value for every field
in the database table.
__ allows get related data, so in your case it could look like this
address.objects.values('c_id__c_id', 'c_id__name', 'c_id__age', 'addr', 'city')

Return all objects relationships recursive

How i can return all relationships on recursive table on django
Structure(model):
class Category(models.Model):
name = models.CharField(max_length=100)
details = models.CharField(max_length=100)
state = models.IntegerField(default=1,choices=estado_choices,)
parent = models.ForeignKey('self', blank=True, null=True, related_name='category', db_index=False)
I would like return like this on template:
_______________________________________________
# |Category |name |description|
________________________________________________
1 | Principal |Example |example 3 |
2 | Subprincipal |subprincipal |example 3 |
3 | Subprincipal 2 |subprincipal 2| example3
i dont know how return this relationship.. please someone idea..!!
Rather that implementing a hierarchical category model of your own. Build on what others have done! There is a library called django-mptt that works very well for this. The documentation will tell you all you need to know about getting a recursive results from your categories.

Django join on multiple foreign fields (left join)

I'm using django 1.10 and have the following two models
class Post(models.Model):
title = models.CharField(max_length=500)
text = models.TextField()
class UserPost(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
approved = models.BooleanField(default=False)
How do I get a list of all the posts including the 'approved' property for the logged in user if exists? So instead of multiple queries, it would be one left join query, pseudo-code:
select * from posts as p
left join user_posts as up
on up.post_id = p.post_id
and up.user_id = 2
Output
post_id | title | text | user_id | approved
1 | 'abc' | 'abc' | 2 | true
2 | 'xyz' | 'xyz' | null | null
3 | 'foo' | 'bar' | 2 | true
I created the models this way because the 'approved' property belongs to the user. Every user can approve/reject a post. The same post could be approved and rejected by other users. Should the models be setup differently?
Thanks
Update:
I'm trying to create a webpage to display all available posts and highlight the ones that the current user approved. I could just list all posts and then for each post check if the 'UserPost' table has a value, if yes get the approved property else ignore. But that means if I have 100 posts I'm making 100 + 1 calls to the db. Is it possible to do 1 call using ORM? If this is not possible, should the models be setup differently?
Then I think you need something like this:
Post.objects.all().annotate(
approved=models.Case(
models.When(userpost_set__user_id=2,
then=models.F('userpost__approved')),
default=models.Value(False),
output_field=models.BooleanField()
)
)

django accessing raw many to many created table fields

Model:
class Subjects (models.Model):
name = models.CharField(max_length=100)
places = models.CharField(max_length=100)
class Student (models.Model):
name = models.CharField(max_length=40)
lastname = models.CharField(max_length=80)
subjects = models.ManyToManyField(Subjects, blank=True)
Django creates appname_student_subjects when I use model above.
appname_student_subjects table looks for example, like this:
id | student_id | subjects_id
-----------------------------------------
1 | 1 | 10
2 | 4 | 11
3 | 4 | 19
4 | 5 | 10
...
~1000
How can I access subjects_id field and count how many times subjects_id exists in the table above (and then do something with it). For example: If subject with id 10 exists two times the template displays 2. I know that I should use "len" with result but i don't know how to access subject_id field.
With foreign keys I'm doing it like this in a for loop:
results_all = Students.objects.filter(subject_id='10')
result = len(results_all)
and I pass result to the template and display it within a for loop but it's not a foreign key so it's not working.
You can access the through table directly.
num = (Students.subjects # M2M Manager
.through # subjects_students through table
.objects # through table manager
.filter(student_id=10) # your query against through table
.count())