Django: Check for related objects and whether it contains data - python

For example, I have two models in a car management system(webpage):
class Brand(models.Model):
brand_name= models.CharField(max_length=100, null=False)
class Cars(models.Model):
car_model= models.CharField(max_length=100, null=False)
car_production_year= models.CharField(max_length=100, null=False)
car_brand= models.ForeignKey(Brand, null=True, blank=True, default = None)
Now, I want to delete a Brand data from the car system. How can I check if this Brand has been used in another model or does that foreign key contains any data(as I have allowed null True for car_brand in Cars model).
PS:
using this function:
self.model._meta.get_all_related_objects():
I got any related object in used in Brand model class. But, I don't know how to get if that related object contains any data.

Use exists(). It's designed to be used for exactly this type of situations:
for brand in Brand.objects.all():
if not brand.cars_set.all().exists():
# delete
Also it's almost always faster than any other type of check because of the way it is designed to work at the database level. You can read details of exists() behaviour in the docs

From this question, for my code, this was faster:
for b in Brand.objects.filter(cars__isnull=True):
# delete
If You have the ids (my case), I used this (60% faster than cars_set):
for brand_id in brand_id_set:
if Brand.objects.filter(id=brand_id).filter(cars__isnull=True):
# delete
I am using Django 1.11

I'd say the easiest way is like so:
# brand is an instance of Brand
if not brand.cars_set.all():
# delete
else:
# do something else
The Django docs cover foreign keys in quite a lot of detail.

cars_with_brands = Car.objects.filter(car_brand__isnull = False)
if cars_with_brands.count() == 0:
# you can delete Brand Model
else:
cars_with_brands.delete()
# you can delete Brand Model

Related

Add columns in model in DJango based on if else condition

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.

Django models - Model relations misunderstandings

I want to create a table that only adds some information about another table. Here is what I have:
I have 2 tables Exchange and ExchangeConnection:
class Exchange(models.Model):
slug = models.CharField(max_length=200, primary_key=True, blank=False, null=False)
name = models.CharField(max_length=200, blank=False, null=False)
class ExchangeConnection(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
exchange = models.OneToOneField(Exchange, on_delete=models.CASCADE)
There are multiple exchanges which are defined by me and won't be modified throughout the app usage. It's only useful stored data to make my app works. I see it more like a type of ExchangeConnection.
Then, I have ExchangeConnection. This table will be modified throughout the app usages because it represents information that belongs to a user, and it will be able to create some:
When the user create an ExchangeConnection, he select which only one Exchange he is using.
In my code you can see I'm using OneToOneField which isn't good because It implies an Exchange can be "linked" only once for every ExchangeConnection.
I don't want to use ForeignKeyField in ExchangeConnection because I don't want ExchangeConnections to be part of an Exchange.
I certainly misunderstood the logic of relations so I may bot be clear...
Short Answer:
ForeignKeyField is the correct option in this case.
Why? (Long Answer)
This statement says that you are thinking in a wrong way.
I don't want to use ForeignKeyField in ExchangeConnection because I don't want ExchangeConnections to be part of an Exchange.
Let's put it this way:
When you use ForeignKeyField in ExchangeConnection, Exchanges will be a linked to or part of ExchangeConnection.
ExchangeConnection won't be a part of Exchange.
For example, lets assume that you have used OneToOneField. There are two users, Sam and Richard.
You have saved first ExchangeConnection object with user = Sam and exchange = Exchange1.
Then you can't save the second ExchangeConnection object with user = Richard and exchange = Exchange1.
What happens in this case?
ExchangeConnection object should not have more than one instance which contains exchange = Exchange1. In other words it should not contains duplicates.
Conclusion:
OneToOneField = ForeignKey + (unique=True)

Django AutoSlugField not considering soft deleted instances by Django Safe Delete

In our model we have a name and slug fields. This is how it looks like:
class MyModel(CommonInfo, SafeDeleteModel):
name = models.CharField(_('Name'), max_length=255, null=True, blank=True)
slug = AutoSlugField(_('Url'), populate_from='name', unique=True,)
For the slug field we generate an unique slug every time our model is saved.
We are also using Django Safe Delete library to soft delete our model:
Django Safe Delete
Django Autoslug
That means that for example if we create a new instance of our model with Name "My Model" it will auto generate a slug that will look like this: "/my-model".
Now let's say we "soft delete" this instance with the slug "/my-model". In our database there will be a property deleted which contains the date when the model was deleted. We don't show this one in our application, it is completely ignored (because it is soft deleted, that's fine).
The problem is that next time we create another one with the same name "My Model" it will auto generate the slug "/my-model" again, not considering that there is already one (which is soft deleted) with the same name and slug. We would need something like "/my-model-1" or whatever that is unique.
We are missing the connection between the autoslug and the safe-delete libraries, somehow the autoslug needs to know that there might be soft deleted ones and consider them when generating the unique slug.
Any help would be really appreciated and please consider that we are totally new in Django / Python.
if this doesn't work, our workaround will be generating the slug using 2 fields (name & id). It will generate a slug that will look like this: "/my-model/12345" and will be always unique since id is unique.
I think we found it.
We needed to create a new Manager that can see all the instances, even the soft deleted ones:
class MyModelAllManager(SafeDeleteManager):
_safedelete_visibility = DELETED_VISIBLE
Then in our model we pass it to the AutoSlugField function:
class MyModel(CommonInfo, SafeDeleteModel):
# We don't know why but it only works if we create a variable and assign the Manager to it. It doesn't work if we pass the Manager directly to the AutoSlugField function.
all_objects = MyModelAllManager()
name = models.CharField(_('Name'), max_length=255, null=True, blank=True)
slug = AutoSlugField(_('Url'), populate_from='name', unique=True, manager=all_objects)
That does the magic.

Django/Python: Best Practice/Advice on handling external IDs for Multiple Multi-directional External APIs

So this is more of a conceptual question, and I am really looking for someone to just help point me in the right direction. I am building a middleware platform where I will be pull data in from inbound channels, manipulating it, and then pushing it out the other door to outbound channels. I will need to store the external id for each of these records, but the kicker is, records will be pulled from multiple sources, and then pushed to multiple sources. A single record in my system will need to be tied to any number of external ids.
a quick model to work with:
class record(models.Model):
#id
Name = models.CharField(max_length=255, help_text="")
Description = models.CharField(max_length=255, help_text="")
category_id = model.ForeignKey(category)
class category(models.Model):
#id
name = models.CharField(max_length=255, help_text="")
description = models.CharField(max_length=255, help_text="")
class channel(models.Model):
#id
name = models.CharField(max_length=255, help_text="")
inbound = models.BooleanField()
outbound = models.BooleanField()
Obviously, I cannot add a new field to every model every time I add a new integration, that would be soooo 90s. The obvious would be to create another model to simply store the channel and record id with the unique id, and maybe this is the answer.
class external_ref(models.Model):
model_name = models.CharfieldField()
internal_id = models.IntegerField()
external_id = models.IntegerField()
channel_id = models.IntegerField()
class Meta:
unique_together = ('model', 'internal_id',)
While my example holds simply 4 models, I will be integrating records from 10-20 different models, so something I could implement an a global level would be optimal. Other things I have considered:
Overwriting the base model class to create a new "parent" class that also holds an alpha-numberic representation of every record in the db as unique.
Creating an abstract model to do the same.
Possibly storing a json reference with channel : external_id that I could ping on every record to see if it has an external reference.
I'm really an open book on this, and the internet has become increasingly overwhelming to sift through. Any best practices or advice would be much appreciated. Thanks in advance.
I have this exact issue and yes there is not much information on the web in using Django this way. Heres what Im doing - haven't used it long enough to determine if its "the best" way.
I have a class IngestedModel which tracks the source of the incoming objects as well as their external ids. This is also where you would put a unique_together constraint (on external_id and source)
class RawObject(TimeStampedModel):
"""
A Table to keep track of all objects ingested into the database and where they came from
"""
data = models.JSONField()
source = models.ForeignKey(Source,on_delete=models.PROTECT)
class IngestedModel(models.Model):
external_id = models.CharField(max_length=50)
source = models.ForeignKey(Source,on_delete=models.CASCADE)# 1 or 0
raw_objects = models.ManyToManyField(RawObject,blank=True)
class Meta:
abstract = True
then every model that is created from ingested data inherits from this IngestedModel. That way you know its source and you can use each external object for more than 1 internal object and vise versa.
class Customer(IngesteModel):
class Order(IngestedModel):
...
etc.
Now this means there is no "IngestedModel" table but that every model has a field for source, external_id and a reference to a raw object (many to many). This feels more compositional rather than inherited - no child tables which seems better to me. I would also love to hear feedback on the "right" way to do this.

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