Add columns in model in DJango based on if else condition - python

This is my Django code for my model
I want to have columns in the model based on the value of chart type enter column there`
class DashboardCreativeQuery(models.Model):
query_name = models.CharField(max_length=256, null=False, unique=True)
query = models.TextField( null=False)
chart_type = models.ForeignKey(DashboardCreativeCharts, blank=True, null=True, related_name='chart_type',
on_delete=models.CASCADE)
if chart_type:
test= JSONField(null=False)
How can I do it?

By default, django, uses a Relational Database. A Relational Database store data in relations:
A relation is defined as a set of tuples that have the same attributes.
That means, in a relation (table) all tulles (rows) must have the same attributes (columns). For this reason, if you are using a relation (a table) to store your data, you should don't change model fields dynamically.
What can you do
Take a look to django model inheritance, maybe it is a solution for you.
Move your solution to a no-sql backend like mongo.

Related

How do I write a Django ORM query where the select table shares a common column with another table?

I'm using Django and Python 3.7. I have these two models. Note they both have a similar field
class Article(models.Model):
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE,)
class WebPageStat(models.Model):
objects = WebPageStatManager()
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, )
score = models.BigIntegerField(default=0)
I would like to write a Django ORM query that selects one of the models but does a join on the shared column in order to do a comparison on the "score" field. I tried the below, but alas the error
Article.objects.filter(publisher=webpagestat.publisher, webpagestat.score__gte==100)
File "<input>", line 1
SyntaxError: positional argument follows keyword argument
How do I include the "WebPageStat" table in my join?
What you want is easily done in Django by using lookups that span relations. In your example you need to add a way of referencing the related objects in the ORM. This is donde by setting the related_name attribute of the ForeignKey fields. Although this is not strictly necessary it is more clear in this way. You can read more about related_name and related_query_name here. In short, your models should look like:
class Article(models.Model):
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, related_name='articles')
class WebPageStat(models.Model):
objects = WebPageStatManager()
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, related_name='stats')
score = models.BigIntegerField(default=0)
Once this is done your query will be carried out by the following code:
Article.objects.filter(publisher__stats__score__gte=100)
What this query is doing in short is selecting every article whose publisher has at least one web page stat whose score is greater than or equal to 100.

What's the use of Intermediate models in Django?

Why do we use an intermediate model?
Can't we just use Many to many relationship without intermediate model?
M2M relationships require intermediate tables. You can read more about what M2M relationships are and why they require an intermediate table (referred to as a junction table in the article) here:
Django abstracts this away by automagically creating this intermediate table for you, unless you need to add custom fields on it. If you do, then you can define it by overriding the through parameter as shown here
Here's a quick picture of why the table is required
Source: https://www.geeksforgeeks.org/intermediate-fields-in-django-python/
Let's say you have two models which have a Many-to-Many relationship, like Customer and Product. One customer can buy many products and a product can be bought by many customers.
But you can have some data that doesn't belong to neither of them, but are important to the transaction, like: quantity or date.
Quantity and date are the intermediary data which are stored in intermediary models.
from django.db import models
class Item(models.Model):
name = models.CharField(max_length = 128)
price = models.DecimalField(max_digits = 5, decimal_places = 2)
def __str__(self):
return self.name
class Customer(models.Model):
name = models.CharField(max_length = 128)
age = models.IntegerField()
items_purchased = models.ManyToManyField(Item, through = 'Purchase')
def __str__(self):
return self.name
class Purchase(models.Model):
item = models.ForeignKey(Item, on_delete = models.CASCADE)
customer = models.ForeignKey(Customer, on_delete = models.CASCADE)
date_purchased = models.DateField()
quantity_purchased = models.IntegerField()
When you buy a product, you do it through the Purchase model: the client customer buys quantity_purchased quantity of items item in date_purchased.
The Purchase model is the Intermediate model.
Django documentation says:
...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.
In this case we have this line in the Customer model, which defines the intermediary model in through = 'Purchase'
items_purchased = models.ManyToManyField(Item, through = 'Purchase')
Let's now use the example from the Django Documentation.
You have a database of musicians with a Many-to-Many relationship with the bands the belong to: a musician can belong can be part of many bands, and the bands can have many musicians.
What data do you want to keep?
For musicians (person): name and instrument they play
For the bands: name and style.
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
age = models.IntegerField()
class Group(models.Model):
name = models.CharField(max_length=128)
style = models.CharField(max_length=128)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
But, wouldn't you think that knowing when the person joined the band is important? What model would be the natural place to add a date_joined field? It makes no sense to add it to Person or Group, because it's not an intrinsic field for each of them, but it's related to an action: joining the band.
So you make a small, but important adjustment. You create an intermediate model that will relate the Person, the Group with the Membership status (which includes the date_joined).
The new version is like this:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
age = models.IntegerField()
class Group(models.Model):
name = models.CharField(max_length=128)
style = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
The changes are:
You added a new class called Membership which reflects the membership status.
In the Group model you added members = models.ManyToManyField(Person, through='Membership'). With this you relate Person and Group with Membership, thanks to through.
Something important to clarify.
An intermediate model, or in relational database terms, an associative entity, are always needed in a Many-to-Many (M2M) relationship.
A relational database requires the implementation of a base relation
(or base table) to resolve many-to-many relationships. A base relation
representing this kind of entity is called, informally, an associative
table... that can contain references to columns from the same or different database tables within the same database.
An associative (or junction) table maps two or more tables together by
referencing the primary keys of each data table. In effect, it
contains a number of foreign keys, each in a many-to-one relationship
from the junction table to the individual data tables. The PK of the
associative table is typically composed of the FK columns themselves. (source)
Django will create the intermediate model, even when you don't explicitly define it with through.
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.
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.(source)

Django OneToOneField and ForeignKeyField add "_id" suffix to the field

When I checked group_cover table which is created by Django, there were group_id_id field and group_cover field.
I'd like to change group_id_id to group_id.
models.py
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length=50, unique=False, blank=False)
class Group_Cover(models.Model):
group_id = models.OneToOneField(Group, primary_key=True) # this create group_id_id
group_cover = models.ImageField(upload_to="/image/group/")
class Group_Member(models.Model):
user_id = models.ForeignKey(User2) # this create user_id_id
group_id = models.ForeignKey(Group) # this create group_id_id
Yeah, if I write,
group = models.OneToOneField(Group, primary_key=True)
It might work, but I may not need "_id" suffix on some field.
I read this document, but owing to my poor English, I couldn't understand the way.
Would you please teach me how to change?
Django adds an _id postix to primary keys that are generated automatically. You generally don't need to worry about them unless using a legacy data base.
Solution 2 would be the one i would recommend for a new project. Solution 1 for legacy databases.
Solution 1
To modify your existing code, use the following db_column attribute as it allows you to name the field in the database.:
group = models.AutoField(primary_key=True, db_column='group_id')
Documentation
Solution 2
To get the same results in a more "Django" way let Django generate the Primary keys automatically then reference the model in the OneToOne and Foreign key fields as shown below.
class Group(models.Model):
group_name = models.CharField(max_length=50, unique=False, blank=False)
class Group_Cover(models.Model):
group = models.OneToOneField(Group)
group_cover = models.ImageField(upload_to="/image/group/")
class Group_Member(models.Model):
user = models.ForeignKey(User2)
group = models.ForeignKey(Group)
Your assumption is correct, you need to rename your fields to not include the _id (i.e group instead of group_id). This will fix your "issue" but more than anything it more accurately represents the relationship/field. You have relationships to a model, not a reference to the id.
_id is an automatic reference provided by django to make it easier to just retrieve the _id from a model.
From the documentation
Behind the scenes, Django appends "_id" to the field name to create its database column name. In the above example, the database table for the Car model will have a manufacturer_id column. (You can change this explicitly by specifying db_column) However, your code should never have to deal with the database column name, unless you write custom SQL. You’ll always deal with the field names of your model object.
You should not worry about _id that is being added in database table. You should not deal with database if you are using ORM in Django. Also, you do not need to specify id unless its special type - group of attributes.
I would do it like this (I believe you do not need that many classes):
class Group(models.Model):
name = models.CharField(max_length=50, unique=False, blank=False)
cover = models.ImageField(upload_to="/image/group/")
users = models.ManyToManyField(User2)
Then you should access attributes with object notation. If you want id, use group.id, if you want to filter object, use Group.objects.filter(id__gt=10) or Group.objects.get(id=1) etc. My model should be doing exactly what you want to achieve.

Python Django - Accessing foreignkey data

I am trying to figure out how to get data from my models with ForeignKey relationships. I have the following models.py:
class wine(models.Model):
name = models.CharField(max_length=256)
year = models.CharField(max_length=4)
description = models.TextField()
class collection(models.Model):
name = models.CharField(max_length=50)
description = models.TextField(null=True)
class collection_detail(models.Model):
collection = models.ForeignKey(collection)
wine = models.ForeignKey(wine)
quantity = models.IntegerField()
price_paid = models.DecimalField(max_digits=5, decimal_places=2)
value = models.DecimalField(max_digits=5, decimal_places=2)
bottle_size = models.ForeignKey(bottle_size)
Wine is a basic table, Collection Detail is a table that references a wine and adds user specific data (like price paid) to it. Collection is a group of collection_detail objects.
I am struggling on how to access data within these models. I can easily display data from a specific model, but when viewing a particular collection, I cannot access the collection_detail.wine.name data. Do I need to write specific queries to do this? Can I access this data from the templating language? My data model appears correct when viewed via the admin, I can add the data and relationships I need.
Thanks for any help!
Use collection_detail_set to obtain a queryset of all collection_detail's with that collection.
If you want a one-to-one relationship instead of a one-to-many (which is what you get using ForeignKey), change
collection = models.ForeignKey(collection)
to
collection = models.OneToOneField(collection)
and access the collection's collection_detail simply by calling collection_detail from your collection model.

queries in django

How to query Employee to get all the address related to the employee, Employee.Add.all() does not work..
class Employee():
Add = models.ManyToManyField(Address)
parent = models.ManyToManyField(Parent, blank=True, null=True)
class Address(models.Model):
address_emp = models.CharField(max_length=512)
description = models.TextField()
def __unicode__(self):
return self.name()
Employee.objects.get(pk=1).Add.all()
You need to show which employee do you mean. pk=1 is obviously an example (employee with primary key equal to 1).
BTW, there is a strong convention to use lowercase letters for field names. Employee.objects.get(pk=1).addresses.all() would look much better.
Employee.Add.all() does not work because you are trying to access a related field from the Model and this kind of queries require an instance of the model, like Ludwik's example. To access a model and its related foreign key field in the same query you have to do something like this:
Employee.objects.select_related('Add').all()
That would do the trick.
employee = Employee.objects.prefetch_related('Add')
[emp.Add.all() for emp in employee]
prefetch_related supports many relationships and caches the query set and reduces the database hits hence increases the performance..

Categories

Resources