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.
Related
I have a shirt which can contain multiple colors, and multiple colors which can have multiple shirts. Normally I would express it the following way:
In django I have the many-to-many (https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/)
Example:
publications = models.ManyToManyField(Publication)
--
Can I create the table "Item_colors" consisting of 2 columns (no "ID" primary key) and design the models according to my diagram using the composite key:
class Item_colors(models.Model):
class Meta:
unique_together = (('cloth_item_id', 'color_id'),)
cloth_item_id = models.ForeignKey(Cloth_item, on_delete=models.CASCADE)
color_id = models.ForeignKey(Color, on_delete=models.CASCADE)
How is the many-to-many relation handled in a DB context, and does it yield better performance?
EDIT: https://code.djangoproject.com/wiki/MultipleColumnPrimaryKeys no avoiding primary keys in favor of composite keys saving columns :( at least for now..
How is the many-to-many relation handled in a DB context, and does it yield better performance?
With a junction table in the middle, so with an item_colors table. But the table contains a primary key, as does every model in Django.
If you do not specify a through=… parameter [Django-doc] to define the model for the junction table yourself, Django will automatically create such model. This model then has two ForeignKeys to the two models it connects as discussed in the database representation section of the documentation:
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many field and the name of the table for the model that contains it. Since some databases don’t support table names above a certain length, these table names will be automatically truncated and a uniqueness hash will be used, e.g. author_books_9cdf. You can manually provide the name of the join table using the db_table option.
But the table thus has a primary key. This might be useful if the same object occurs a second time in the relation.
You can access the through model in the Article-Publication example for example with:
Article.publications.through
You thus can define a through model yourself, for example with:
class Color(models.Model):
color = models.CharField(max_length=128)
class ClothItem(models.Model):
item_name = models.CharField(max_length=128)
colors = models.ManyToManyField(
Color,
related_name='cloth_items'
through='ClothItemColors'
)
class ClothItemColors(models.Model):
cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
color = models.ForeignKey(Color, on_delete=models.CASCADE)
class Meta:
db_table = 'item_colors'
constraints = [
models.UniqueConstraint(
fields=('cloth_item', 'color'),
name='unique_cloth_color'
)
]
often an explicit through model is used to store extra information, for example the quantity:
class ClothItemColors(models.Model):
cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
color = models.ForeignKey(Color, on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
# …
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)>
I'm using django-sphinxql for search requirements in my django project.
I want to use two models in my app for search with some query. Models look as below
Class Model1(models.Model):
name = models.CharField(max_length=50)
model2 = models.ForeignKey(Model2, on_delete=models.CASCADE)
Class Model2(models.Model):
caption = models.CharField(max_length=50)
I want to enable search for both name and caption fields above such that Model1 is returned for any matches, e.g. if query="abc" matches caption the response should be Model1,
How would I achieve that I've created index for Model1 but don't know how to add caption from Model2 in it as well. My index for Model1 is as below
class Model1Index(indexes.Index):
name = fields.Text(model_attr='name')
class Meta:
model = Model1
settings.INDEXES['source_params'] = {'sql_field_string': ['name'],}
Quick help is appreciate.
For foreign key fields in Sphinx we can use double underscores(__) to point to specific field for indexing. User model_attr for this
In above example
class Model1Index(indexes.Index):
name = fields.Text(model_attr='name')
caption = fields.Text(model_attr='model2__caption')
class Meta:
model = Model1
settings.INDEXES['source_params'] = {'sql_field_string': ['name'],}
can be defined.
Reference http://django-sphinxql.readthedocs.io/en/latest/indexes.html
I'm learning Django and trying to get the hang of querying foreign keys across a bridging table. Apologies if this is a duplicate, I haven't been able to find the answer by searching. I've got models defined as follows
class Place(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
class PlaceRef(models.Model):
place = models.ForeignKey(Place) # many-to-one field
entry = models.ForeignKey(Entry) # many-to-one field
class Entry(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=10)
If I want to retrieve all the Entries associated with a particular Place, how do I do it?
place = get_object_or_404(Place, id=id)
placerefs = PlaceRef.objects.filter(place=place)
entries = Entry.objects.filter(id.....)
Also, if there is a more sensible way for me to define (or get rid of) PlaceRefs in Django, please feel free to suggest alternatives.
Thanks for helping out a beginner!
First, I'd suggest rewriting the models to:
class Place(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
class Entry(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=10)
places = models.ManyToManyField(Place, related_name='places')
So you can query:
Entry.objects.filter(places__id=id)
In your current model:
Entry.objects.filter(placeref_set__place__id=id)
Note that the double underscore __ is used to jump from one model to the next. Also, django creates some fields on the model that help you navigate to related objects. In this example: Entry.placeref_set. You can read more about it here:
http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
I'm attempting to construct a Django application that models an existing set of tables. These tables all have the same fields, plus custom fields per table. What I'm wanting to do is model this structure, and have records save to a particular table based on what table model they are attached to.
These tables can be created quite often, so it is unfeasible to construct new models per table.
Perhaps the code will demonstrate what I'm trying to do more clearly:
class CustomField(models.Model):
column_name = models.CharField(max_length=100)
description = models.CharField(max_length=255, blank=True, null=True)
class CustomData(models.Model):
custom_field = models.ForeignKey(CustomField)
value = models.CharField(max_length=100, blank=True, null=True)
# value will always be a nullable varchar(100)
class Table(models.Model):
table_name = models.CharField(max_length=255)
name = models.CharField(max_length=100)
custom_fields = models.ManyToManyField(CustomField)
class Record(models.Model):
table = models.ForeignKey(Table)
... list of common fields omitted ...
custom_values = models.ManyToManyField(CustomData)
When saving a new record that has a foreign key to 'table_1', I would like the eventual operation to be along the lines of insert into table_1 (..fields..) values (..field values..)
Is this possible? I guess I could hook into signals or the save method, but I'd like to find the simplest approach if such exists.
You can create unmanaged models dynamically. You just need to create a dict mapping column names to the data values. Once you have that, you can do the following:
from django.db import models
# This is the dict you created, mapping column names to values
values = {col_1: value_1, col_2: value_2, col_3: value_3, ... }
# Create a dict defining the custom field types, eg {col_name: django_field}
attrs = dict((c, models.CharField(max_length=100, blank=True, null=True)) for c in values)
# Add a Meta class to define the table name, eg table_1
class Meta:
app_label = myapp
db_table = 'table_1'
managed = False
attrs['Meta'] = Meta
attrs['__module__'] = 'path.to.your.apps.module'
DynamicModel = type('MyModel', (models.Model,), attrs)
# Save your data
DynamicModel.objects.create(**values)
Wrap this up in a function, and put it in your .save() method on Record. If you have any common fields, you can add them to attrs, or even better: create an abstract model with all the common fields and inherit that in the last line above instead of models.Model.