I am working on a project where I have 2 models model
class Customer(models.Model):
name = models.CharField(...)
...
class CustomerProperty(models.Model):
name = models.CharField(...)
type = models.CharField(...)
code = models.CharField(...)
The CustomerProperty table has rows inside based on a parquet file (created at database init, not changed later on). For column in the parquet file, CustomerProperty has a row with column name from parquet as name in the table.
Now for some other purpose, I need to copy over all the data in the parquet file inside the db. So, for each row in the CustomerProperty table, this new table will have a column (plus one column for foreign key to Customer) so I can run filters based on property values. This will also be copied over at db init and not change later on, so it is an unmanaged django model.
I can't find any good docs on this, how to create a django model dynamically or how to add fields to that model dynamically. I don't need it to be managed, no need of migrations or django admin view support. I only need it to work with django ORM and be able to join and filter on it.
I've read the docs and didn't find much. Most of the answers talk about why this is a bad idea but I don't see any other way of solving my problem (I have few other tables joined together to run a complex query and I need to do further filtration based on these properties and support pagination.
Related
I'm using python and psycopg2 to scrape some data and insert them into my database.
I've already created the movies and actors tables inside my Django models.py and inside my movies table, there is a many to many relationship between movies and actors table.
below is my models.py:
class Movie(models.Model):
name = models.CharField(max_length=55)
summary = models.TextField(max_length=1024)
actor = models.ManyToManyField(Actor, blank=True)
when I create a movie from Django-admin I select which actors are included in the movie and everything works fine and all the related actors for that movie will show up on my website.
But the problem is that when I try to insert scraped data into my database outside of my Django project folder, the related actors won't be shown on my website because obviously, I have not set the many to many relationship between them.
I have tried creating a junction table using SQL commands which gets the movie id and the actor's id and links them together but I don't know how I should tell Django to use that table and show the related actors for each movie.
This is the SQL code I use to insert into my db:
INSERT INTO movies(name, summary)
VALUES ('movie name', 'sth')
and the code to insert to actors table:
INSERT INTO actors(name, bio)
VALUES ('actorname', 'sth')
Both actors and movies table have auto generated id and I insert them insto the junction table using the code below:
INSERT INTO movie_actors (actor_id, movie_id)
VALUES (
(SELECT actor_id from actors where name='actor name'),
(SELECT movie_id from movie where name='movie name')
)
Am I doing it right?
I would really appreciate it if someone could help me with this.
Django automatically creates a table for many2many relationships. From docs:
ManyToManyField.through
Django will automatically generate a table to manage many-to-many relationships. However, if you want to manually specify the intermediary table, you can use the through option to specify the Django model that represents the intermediate table that you want to use.
The most common use for this option is when you want to associate extra data with a many-to-many relationship.
So you must find the name of the table that django had already created.
Secondly, I suggest that you use django's ORM instead of raw queries so you don't have these kind of problems anymore.
Django automatically creates a through table for M2M relations, if you need you can specify custom through table. In your case I think there is no need of custom through table.
I using Django ORM instead of writing raw query.
INSERT INTO movies(name, summary) VALUES ('movie name', 'sth')
instead of tis raw query you can use the following ORM query:
movie = Movie.objects.create(name="movie name", summary="movie sammuary")
This will create a movie entry in the Movie table.
Next to create user entry you can use the following query:
actor = Actor.objects.create(name="actor name", bio="actor bio")
Now you created the entries in both the table, next you can establish the realtion, for that you have to use the following query:
movie.actor.add(actor)
Incase if you want to add multiple actors at the same time, you create multiple actors object and use following query:
movie.actor.add(actor1, actor2, actor2)
For more details you can check django's offical documentation
My model :
class Image(models.Model):
name=models.CharField(max_length=40,unique=True,help_text="name of the image")
tags = models.ManyToManyField(Tag)
class Tag(models.Model):
tag = models.CharField(max_length=100,unique=True)
here when I do makemigrations and migrate it is creating 3 tables inside my database 1.image 2.tag 3.image_tags table
so, my question is i am not specifying image_tags table in my models.py file ,from where django is creating image_tags table and what is the flow ??
I have checked in migrations file but I didnot get any clarity regarding this
An intermediary table is required for a Many-To-Many relationship in a database, and because most of the time you don't need to store extra data on the relationship, Django just silently creates this table for you. In your case it will create a table with 3 fields: id, image_id, tag_id.
If you want to specify your own intermediary table, for example if you want to store extra data, you can create a model with ForeignKey's to your related tables and then define your ManyToManyField with a "through" argument like so:
class ImageTag(models.Model):
image = models.ForeignKey('Image')
tag = models.ForeignKey('Tag')
extra_data = models.CharField()
class Tag(models.Model):
name = models.CharField()
class Image(models.Model):
name = models.CharField()
tags = models.ManyToManyField(Tag, through=ImageTag)
Actually, that is not Django Functionality. It's SQL functionality. SQL is creating the internal table. Because SQL can't create reference, it's not Foreign key. That's why this Bridging table concept is emerged. It will resolve the problem as well as it will hold data(ID) of both tables and few custom fields, depends on requirements.
Updated with new req:
Refer this:
https://gist.github.com/jacobian/827937
Django 1.8 - Intermediary Many-to-Many-Through Relationship - What is the consequence of where 'ManytoManyField' is used?
From my point of view, It's not good practice to customize the bridging table. You can specify the extra fields to any of two tables orelse create a new table make it as foreign key
I am used in creating orm and leaving django responsible for creating the tables.But in a project I am involved I have to create a simple CRUD application a frontend for an existing database. The database was created by creating the tables manually. So I have two tables Table1 and Table2 which have a many to many relationship through Tables12. Tables12 looks like the table that django would normaly create using a ManyToManyField thus it has two fields the id's of the two models. So after using django's inspectdb, django successfully created the models according to the SQLite database. The many to many tables like Tables12 was created like the following(as stated above):
class Tables12(models.Model):
table1 = models.ForeignKey(Table1)
table2 = models.ForeignKey(Table2)
class Meta:
managed = False
db_table = "Tables12"
unique_together = (("table1_id", "table2_id"),)
Trying the following gives me an error:
>> table2 = Table2.objects.get(pk=1)
>>tables12 = Tables12.objects.filter(table2=table2)
>>tables12
OperationalError: no such column: Tables12.id
I am guessing Django's orm is expecting an id field in every models created. How can I bypass this behavior? Is there a way to edit the tables so as they look more like django's orm but behave as the existing db's tables? Like:
class Table1(models.Model):
#pre exsiting fields
table2 = models.ManyToManyField(Table2)
or
class Table2(models.Model):
#pre existing fields
table1 = models.ManyToManyField(Table1)
but without destroying database records and without creating tables from start.
You can remove the Tables12 model, and specify the db_table argument to a ManyToManyField:
class Table1(models.Model):
tables2 = models.ManyToManyField(Table2, db_table='Tables12')
You would still not be able to query the Tables12 model directly (it still exists and has an id field), but this would allow you to use the JOINs Django generates for a ManyToManyField:
table1 = Table1.objects.get(pk=1)
tables2 = table1.tables2.all()
This would still not allow you to use Django to write to the join table, but it allows you to use the data that's in it. If at all possible, I'd strongly recommend adding a primary key.
I want to use a dynamic field in django means I have one model whose one is what be specified in the other model.
I hope i can explain it to you through example.
I have one model name product and each time a new product is uploaded we have to set some attributes for that and that attributes are specified in the 2nd table means in this product model one field is dynamic which depends on the 2nd table. if i select 'x' in other table then that field is shown here and if i select 'y' then that will be shown here,So that based on that product id and attribute id I can specify the attribute value in 3rd table so that in future i can fetch that value for a specified product.
I have tried this a lot but i do not know how to use dynamic fields in django, So can anybody let me know how i can do this.
Thanks
I recommend you to use django-json-field for that purpose ( https://github.com/derek-schaefer/django-json-field ). It uses only one Text field in your db, but you can access objects in your json like a python objects:
json = JSONField() #in your model
json = "{'attributes':{'colour':'blue','size':'2'}, 'image-height':'200px'}" # in your db
{{product.json.attributes}} #in your template
product.json.attributes #in your views
It's a great way to make many 'django' fields, while storing it only in one Text field in db.
The disadvantages of this approach is that you can't effectively search for the fields using your database, but if you have a few dozens of products, you can do the filter by python right in view.
I'm trying to optimise my app by keeping the number of queries to a minimum... I've noticed I'm getting a lot of extra queries when doing something like this:
class Category(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=127, blank=False)
class Project(models.Model):
categories = models.ManyToMany(Category)
Then later, if I want to retrieve a project and all related categories, I have to do something like this :
{% for category in project.categories.all() %}
Whilst this does what I want it does so in two queries. I was wondering if there was a way of joining the M2M field so I could get the results I need with just one query? I tried this:
def category_list(self):
return self.join(list(self.category))
But it's not working.
Thanks!
Which, whilst does what I want, adds an extra query.
What do you mean by this? Do you want to pick up a Project and its categories using one query?
If you did mean this, then unfortunately there is no mechanism at present to do this without resorting to a custom SQL query. The select_related() mechanism used for foreign keys won't work here either. There is (was?) a Django ticket open for this but it has been closed as "wontfix" by the Django developers.
What you want is not seem to possible because,
In DBMS level, ManyToMany relatin is not possible, so an intermediate table is needed to join tables with ManyToMany relation.
On Django level, for your model definition, django creates an ectra table to create a ManyToMany connection, table is named using your two tables, in this example it will be something like *[app_name]_product_category*, and contains foreignkeys for your two database table.
So, you can not even acces to a field on the table with a manytomany connection via django with a such categories__name relation in your Model filter or get functions.