Why Django ORM failing on simple foreign key relation? - django

I'm trying to simply create one to many relation model of categories using Django amazing ORM.
SQL:
create table categories(
id serial primary key not null,
parent_id int
);
insert into categories values(default,default,default);
update categories set parent_id = 1 where id > 1;
select * from categories;
id | parent_id
----+-----------
2 | 1
3 | 1
1 |
(3 rows)
Django amazing orm model:
class Categories(models.Model):
id = models.AutoField(primary_key=True)
parent_id = models.ForeignKey('self')
class Meta:
managed = False
db_table = 'categories'
Django Query:
Categories.objects.get(id=1)
OUTPUT:
django.db.utils.ProgrammingError: column categories.parent_id_id does not exist
LINE 1: SELECT "categories"."id", "categories"."parent_id_id" FROM "...
^
HINT: Perhaps you meant to reference the column "categories.parent_id".
Why it uses parent_id_id column instead of parent_id and how I can force it to use parent_id?
EDIT
I just changed parent_id field to parent.
EDIT 2
tatlar answer is not in my case becouse i already have database schema.
So after digging more deeper in documentation and other questions on stackoverflow there is what i have in result. This model contains reference to parent and children categories for each row. It could be inherited for all graph alike data models (comments, categories etc).
class Categories(models.Model):
id = models.AutoField(primary_key=True)
parent = models.ForeignKey('self', on_delete=None, parent_link=True, related_name='children')
class Meta:
managed = False
db_table = 'categories'
Get all children for category 1:
from myapp.models import Categories
ch = Categories.objects.get(id=1).children print (ch)
# <QuerySet [<Categories: Categories object (2)>, <Categories: Categories object (3)>]>
Get parent for category 2:
from myapp.models import Categories
ch = Categories.objects.get(id=1).parent
print (ch)
# <Categories: Categories object (1)>

Sorry to hear that you are having trouble with Django. In time you may grow to love the Django ORM and how it abstracts all the SQL code for you :)
You need to dig a little deeper into how the ORM works -- it's not a 1:1 replacement for SQL code. Check out the Model docs.
In your specific case, you need to create a new class called Parent and reference that class (via a ForeignKey) from your Categories class (you might also like to rename your Categories class to Category -- the ORM also handles plurals).
Try the code below (where I have already renamed Categories to Category for you):
from django.db import models
class Category(models.Model):
id = models.AutoField(primary_key=True)
parent = models.ForeignKey(Parent)
# ... Extra model attributes
class Meta:
verbose_name_plural = "categories"
class Parent(models.Model):
id = models.AutoField(primary_key=True)
# ... Extra model attributes
Then add all the extra attributes you need. This will create all the database tables, and their relationships, without you ever writing any SQL. If you are used to writing SQL it is a change, but it makes sense as you work more with the ORM and understand how good it is actually architected.
Good luck!

tatlar answer is not in my case becouse i already have database schema.
So after digging more deeper in documentation and other questions on stackoverflow there is what i have in result. This model contains reference to parent and children categories for each row. It could be inherited for all graph alike data models (comments, categories etc).
class Categories(models.Model):
id = models.AutoField(primary_key=True)
parent = models.ForeignKey('self', on_delete=None, parent_link=True, related_name='children')
class Meta:
managed = False
db_table = 'categories'
Get all children for category 1:
from myapp.models import Categories
ch = Categories.objects.get(id=1).children
print (ch)
# <QuerySet [<Categories: Categories object (2)>, <Categories: Categories object (3)>]>
Get parent for category 2:
from myapp.models import Categories
ch = Categories.objects.get(id=1).parent
print (ch)
# <Categories: Categories object (1)>

Related

Performing a Subquery, Sum and Join in django ORM

I have 2 django models which aren't linked by ForeignKey due to legacy system.
class Parent(model):
name -> CharField()
class Child(model)
parent_name -> CharField()
cost -> IntegerField()
I want to achieve a left join which gives me all parent columns along with sum of cost column from children.
SQL in postgres translates to
select parent.name, sum(child.cost) as cost from parent join child on parent.name = child.parent_name group by parent.name;
Is there any way to achieve this with django ORM
I have tried a lot of things but https://code.djangoproject.com/ticket/28296 might be what is blocking.
Please use a ForeignKey to refer to a parent, not a CharField that joins on the name. This will guarantee referential integrity, avoid data duplication and makes it more convenient to query in Django.
You thus define the models as:
class Parent(models.Model):
name = models.CharField(max_length=128)
class Child(models.Model):
parent = models.ForeignKey(
Parent,
on_delete=models.CASCADE
)
cost = models.IntegerField()
or if the name of the Parent is unique, you can let it refer to the name:
class Parent(models.Model):
name = models.CharField(max_length=128, unique=True)
class Child(models.Model):
parent = models.ForeignKey(
Parent,
to_field='name',
db_column='parent_name',
on_delete=models.CASCADE
)
cost = models.IntegerField()
then you can .annotate(…) [Django-doc] the Parent model with:
from django.db.models import Sum
Parent.objects.annotate(
cost=Sum('child__cost')
)
the Parent objects that arise from this queryset will have an extra attribute .cost that will contain the sum of the costs of the Childs that point to that Parent.

How to add id (instead of object) in ManyToManyField of Django model?

models.py :
class Employee(models.Model):
name = models.CharField(max_length=100)
class Department(models.Model):
name = models.CharField(max_length=100)
employee = models.ManyToManyField(Employee, null=True, blank=True)
I need to save employee ids (instead of employee object) in 'employee' ManyToManyField of 'Department' model. How to do that?
views.py:
dept = Department(name=name)
dept.save()
employee_ids = [1,2]
We can use method add (Django Docs):
Adds the specified model objects to the related object set.
dept = Department.objects.create(name=name)
dept.employee.add(*[1, 2])
Or method set(Django Docs):
Replace the set of related objects
dept.employee.set([1, 2])
Note that add(), create(), remove(), clear(), and set() all
apply database changes immediately for all types of related fields. In
other words, there is no need to call save() on either end of the
relationship.
I think this question is unclear what exactly are you trying to do ?
If you want to create a relation between department and employee on the database level django does that for you
on your current structure the relation and is like
id|department_id|user_id
--|-------------|-------
1| 3 | 2

how to insert in parent model if i add in chield model in django using django admin

i have 3 Models as the follwing:
1- parent models "Batches" contain id & tabel name
class Batch(models.Model):
table_name = models.CharField(max_length=255)
2- Chield model 1 "Table 1"
class Table1(models.Model):
text = models.CharField(max_length=255)
batch_num = models.ForeignKey(Batch, on_delete=models.CASCADE)
3- Chield model 1 "Table2"
class Table2(models.Model):
text = models.CharField(max_length=255)
batch_num = models.ForeignKey(Batch, on_delete=models.CASCADE)
i need if add any transaction in table1 or table2 cereat transaction in parent model "Batch" and fill class name in parent table.
is there any good idea to make this throug django admin
for more explanation i want to make one table include all transaction of my project and name of class that create this transaction
any idea will help me
note:
i tried TabularInline but this is work when i add parent frist then allocate chield to parent.
You can write Triggers for that.
from django.db import connection #imports connection
cursor = connection.cursor() #creates cursor
raw_query = ''' Your Trigger code goes here '''
cursor.execute(raw_query) #execute the database query
I hope you find this helpfull.

How can I create and link many-to-many tables in Django?

I am implementing the following schema in a Django app, but I am new to Django's ORM:
Briefly, a DayMenu lists multiple MenuItems. (A MenuItem is simply a many-to-many relationship between a DayMenu and a Meal.) Each User selects a MenuItem from the DayMenu. (This choice is represented as a UserItemChoice.)
In our first draft models.py (below), MenuItem is defined as a many-to-many field on the DayMenu model.
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Meal(models.Model):
# field options: diet
MEAT = "MEAT"
VEGETARIAN = "VEGET"
HALAAL = "HALAA"
DIET_CHOICES = (
(MEAT, "Meat"),
(VEGETARIAN, "Vegetarian"),
(HALAAL, "Halaal"),
)
# field options: type
FREE = "FREE"
PAID = "PAID"
SKIP = "SKIP"
TYPE_CHOICES = (
(FREE, "Free"),
(PAID, "Paid"),
(SKIP, "Skip"),
)
# fields
cost = models.IntegerField(default=10)
description = models.CharField(max_length=120)
diet = models.CharField(max_length=5, choices=DIET_CHOICES)
type = models.CharField(max_length=5, choices=TYPE_CHOICES)
class DayMenu(models.Model):
# fields
date = models.DateField()
locked = models.BooleanField(default=False)
item = models.ManyToManyField(Meal) # TODO: confirm (replaces MenuItem in schema)
# class UserItemChoice(models.Model):
#
# # fields
# user = models.CharField() # FIXME
# menuitem = models.CharField() # FIXME
# selected = models.BooleanField(default=False)
# like = models.NullBooleanField(default=None)
How do we define UserItemChoice given that:
it is itself a many-to-many relationship
it links to a many-to-many field rather than a (explicit) model
it would (ideally?) be a many-to-many field on the built-in user table
I think what you want is to define UserItemChoice as a through model of m2m relationship between User and MenuItem. through model is mainly used when you want to define some extra attributes between the m2m relationship.
Here a user could have multiple MenuItems, but you would also want attributes like selected and like attributes coming with the relationship, but moving these 2 attributes to either model is no good, hence the through is the best solution.
Check out django doc about through definition and example.

Modelling a relationship to a meta-table with 2 primary keys

I am very new to Django and would appreciate your help with this problem:
I have a table with meta-informationen (like the number of clicks, votes, comments ...) for different areas of my website (news, events in the calendar, films ..). The table is referenced by two primary keys (fi = INTEGER and tbl = CHAR).
class News(models.Model):
title = models.CharField()
...
class Film(models.Model):
title = models.Charfield()
...
class Calendar(models.Model):
title = models.Charfield()
...
class MetaInfo(models.Model):
fi = ForeignKey(??) # Integer
tbl = ForeignKey(??) # CharField
Example: fi = 1 and tbl = 'news' would relate to news-entry with primary key 1. And fi = 100, tbl = 'film' would relate to film-entry with primary key 100.
How to implment this? Is this even possible with django?
Django has a built-in feature called Generic Foreign Keys that allow you to tie a single table to multiple models in this fashion.
This is how you would create your models:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class News(models.Model):
title = models.CharField()
...
class Film(models.Model):
title = models.Charfield()
...
class Calendar(models.Model):
title = models.Charfield()
...
class MetaInfo(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
If you wish, you can be more explicit about the relationship between a model and MetaInfo by using GenericRelation. For example:
class Film(models.Model):
title = models.CharField()
metainfo = generic.GenericRelation('MetaInfo')
...
This allows you to access the related MetaInfo records directly from the Film model, as in
f = Film.objects.get(pk=1)
for mi in f.metainfo.all():
#mi is a matching MetaInfo record for Film record with pk=1
Just to elaborate a bit:
In the MetaInfo model, content_type serves as the equivalent of your tbl column (although it points to a Django construct called a ContentType; Django constructs one for each model in the app/set of apps) and object_id corresponds to your fi key. You actually generally don't pay much attention to those fields. Instead, you get and set the content object, which is the corresponding record. For example, instead of storing or retrieving tlb='Film', fi=1, you'd get or set content_object which corresponds directly to the Film record matching pk=1.
In essence, contenttype__name='Film', object_id=1 while content_object=Film.object.get(pk=1)
This is all assuming that this database is for Django use only. If it's an existing database that you're trying to use within Django, there isn't a straightforward way to handle this that I'm aware of.