django - Runpython function to turn charfield into foreignkey - python

I've been strugglin to relate a csv imported data model with a spatial data model based on a CharField.
I've created both models and now im trying to transfer the data from one field to a new one to be the ForeignKey field. I made a Runpython funtion to apply on the migration but it goives the an error:
ValueError: Cannot assign "'921-5'":
"D2015ccccccc.rol_fk" must be a "D_Base_Roles" instance.
Here are the models:
class D_Base_Roles(models.Model):
predio = models.CharField(max_length=254)
dest = models.CharField(max_length=254)
dir = models.CharField(max_length=254)
rol = models.CharField(primary_key=True, max_length=254)
vlr_tot = models.FloatField()
ub_x2 = models.FloatField()
ub_y2 = models.FloatField()
instrum = models.CharField(max_length=254)
codzona = models.CharField(max_length=254)
nomzona = models.CharField(max_length=254)
geom = models.MultiPointField(srid=32719)
def __str__(self):
return str(self.rol)
class Meta():
verbose_name_plural = "Roles"
class D2015ccccccc(models.Model):
id = models.CharField(primary_key=True, max_length=80)
nombre_archivo = models.CharField(max_length=180, blank=True, null=True)
derechos = models.CharField(max_length=120, blank=True, null=True)
dir_calle = models.CharField(max_length=120, blank=True, null=True)
dir_numero = models.CharField(max_length=120, blank=True, null=True)
fecha_certificado = models.CharField(max_length=50, blank=True, null=True)
numero_certificado = models.CharField(max_length=50, blank=True, null=True)
numero_solicitud = models.CharField(max_length=50, blank=True, null=True)
rol_sii = models.CharField(max_length=50, blank=True, null=True)
zona_prc = models.CharField(max_length=120, blank=True, null=True)
##NEW EMPTY FOREIGNKEY FIELD
rol_fk = models.ForeignKey(D_Base_Roles, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return str(self.numero_certificado)
class Meta:
managed = True
#db_table = 'domperm2015cip'
verbose_name_plural = "2015 Certificados Informaciones Previas"
ordering = ['numero_certificado']
The Runpython function:
def pop_rol(apps, schema_editor):
roles = apps.get_model('b_dom_edificacion', 'D2015ccccccc')
for r in roles.objects.all():
rol = roles
r.rol_fk = r.rol_sii
r.save()
D_Base_Roles.rol values are all unique, and 921-5 is one of those values.
What am I missing?

You probably need to assign an object, not a string. Change the line
r.rol_fk = r.rol_sii
to
r.rol_fk = D_Base_Roles.objects.get(rol=r.rol_sii)
Maybe adjust to whatever the correct field for looking up D_Base_Roles instances is.
Note: this will make a database query for every iteration of the for-loop

Related

Django Relational managers

I was trying to delete my Apllication model:
class Application(models.Model):
app_type = models.ForeignKey(ApplicationCategory, on_delete=models.CASCADE, related_name='applications')
fio = models.CharField(max_length=40)
phone_number = models.CharField(max_length=90)
organisation_name = models.CharField(max_length=100, null=True, blank=True)
aid_amount = models.PositiveIntegerField()
pay_type = models.CharField(max_length=1, choices=PAY_CHOICES, default=PAY_CHOICES[0][0])
status = models.ForeignKey(AppStatus, on_delete=models.CASCADE, related_name='applications', null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
benefactor = models.ForeignKey(Benefactor, on_delete=models.CASCADE, related_name='applications', null=True)
def __str__(self):
return f"id={self.id} li {self.fio} ning mablag\'i!"
and this was my Benefactor model:
class Benefactor(models.Model):
fio = models.CharField(max_length=255)
phone_number = models.CharField(max_length=9)
image = models.ImageField(upload_to='media/')
sponsory_money = models.IntegerField()
organisation_name = models.CharField(max_length=55, null=True, blank=True)
def __str__(self):
return f"{self.fio}"
But I got the below message on superAdmin Panel:
TypeError at /admin/api/benefactor/
create_reverse_many_to_one_manager.\<locals\>.RelatedManager.__call__() missing 1 required keyword-only argument: 'manager'
I would expect delete smoothly!!
Your Benefactor model has several ForeignKey relationships that share the related_name. Give each a unique name and rerun your migrations.

django - how can I get a list of all foreignkeys related to a model?

models.py
class DataSource(VoteModel, models.Model):
​
dataset_request = models.ForeignKey(
'DatasetRequest', on_delete=models.CASCADE, blank=True, null=True)
file = models.FileField(upload_to='datasource_files/')
file_size = models.BigIntegerField(blank=True, null=True)
​
title = models.CharField(max_length=255, default="Untitled")
description = models.TextField(blank=True, null=True)
slug = models.SlugField(blank=True, null=True)
​
is_public = models.BooleanField(default=True)
creator = models.ForeignKey(User, on_delete=models.CASCADE)
​
is_csv_or_tsv = models.BooleanField(null=True)
​
thumbnail = models.ImageField(
upload_to="datasource_thumbnails/", blank=True, null=True)
​
date_uploaded = models.DateTimeField(
auto_now_add=True, blank=True, null=True)
​
comments = GenericRelation(Comment)
​
​
class DatasetRequest(VoteModel, models.Model):
reward = models.DecimalField(
decimal_places=2, max_digits=10) # if 0, 1 medal
title = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
slug = models.SlugField(blank=True, null=True)
is_public = models.BooleanField(default=True)
creator = models.ForeignKey(User, on_delete=models.CASCADE)
thumbnail = models.ImageField(
upload_to="datasetrequest_thumbnails/", blank=True, null=True)
​
best_dataset_entry = models.ForeignKey(
DatasetEntry, on_delete=models.CASCADE, blank=True, null=True)
date_uploaded = models.DateTimeField(
auto_now_add=True, blank=True, null=True)
​
is_paid = models.BooleanField(default=False)
​
comments = GenericRelation(Comment)
​
qa_testers = models.ManyToManyField(User, related_name='qas')
With the following setup, how can I get all DatasetRequests for a given DataSource? dataset_request (DatasetRequest) is a foreignkey in DataSource. There is no many-to-many in DatasetRequest, though there are data sources for every DatasetRequest. Do I need a many-to-many for either?
You can use the accessor for the backwards relationship of your model.
From the Django documentation:
Django also creates API accessors for the “other” side of the
relationship – the link from the related model to the model that
defines the relationship. For example, a Blog object b has access to a
list of all related Entry objects via the entry_set attribute:
b.entry_set.all().
This uses the related_name field specified in the ForeignKey field, but is set to the model name by default.
In your example, you can do:
data_source = DataSource.objects.get(pk=1) # or whatever
data_requests = data_source.datarequest_set.all()
Now data_requests will be a QuerySet of all DataRequest objects that have a foreign key pointing to the data_source.

DRF - filter across 2 models

I'm working with a legacy database where I have a serializer setup on Table A like so -
class TblapplicationsSerializer(serializers.ModelSerializer):
class Meta:
model = Tblapplications
fields = ('applicationid', 'applicationname', 'description', 'drtierid', 'saglink', 'supportinstructions',
'defaultincidentpriorityid', 'applicationorigintypeid', 'installationtypeid', 'comments',
'lastmodifieddate', 'lastmodifiedby', 'assetstatusid', 'recordownerid', 'adl_app')
depth = 2
I'm using a standard filter -
class TblapplicationsFilter(django_filters.FilterSet):
name = django_filters.CharFilter(name="applicationname", lookup_type="exact")
env = django_filters.CharFilter(name="adl_app__environmentid__domain")
class Meta:
model = Tblapplications
fields = ['applicationname', 'name', 'env']
Here's where it goes sideways. What I want to be able to do is filter on my URL like /api/applications/?name=xxx&env=DEV. It would then return the application and any databases that are linked with the environment of DEV. The name was understandably easy, but the only was I figured out the environment was to make the api point for applications touch the middle table that links the two but it returns multiple values because it's grabbing each time application is referenced with a separate database.
I've updated the Serializer and Filter based on comments given and the serializer, without the &env=DEV returns all the appropriate data (domain is nested in a reverse relationship). I then want my filter to filter the results based on that. Which means that it needs to somehow know to limit the results on the reverse relationship to only what's provided from the nested value.
If you see my models -
class Tblapplicationdatabaselinks(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
applicationid = models.ForeignKey('Tblapplications', db_column='applicationId', to_field='applicationid',
related_name='adl_app')
dbid = models.ForeignKey('Tbldatabases', db_column='dbId', to_field='id', related_name='adl_db')
environmentid = models.ForeignKey('Tbldomaincodes', db_column='environmentId', to_field='id',
related_name='adl_envlink')
comments = models.TextField(blank=True)
lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
# upsize_ts = models.TextField(blank=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'tblApplicationDatabaseLinks'
class Tblapplications(models.Model):
applicationid = models.AutoField(db_column='applicationId', primary_key=True)
applicationname = models.CharField(db_column='applicationName', max_length=255)
description = models.TextField(blank=True)
drtierid = models.ForeignKey(Tbldomaincodes, db_column='drTierID', blank=True, null=True, to_field='id',
related_name='app_drtier')
saglink = models.TextField(db_column='sagLink', blank=True)
supportinstructions = models.TextField(db_column='supportInstructions', blank=True)
defaultincidentpriorityid = models.IntegerField(db_column='defaultIncidentPriorityId', blank=True, null=True)
applicationorigintypeid = models.IntegerField(db_column='applicationOriginTypeId')
installationtypeid = models.ForeignKey(Tbldomaincodes, db_column='installationTypeId', to_field='id',
related_name='app_insttype')
comments = models.TextField(blank=True)
assetstatusid = models.ForeignKey(Tbldomaincodes, db_column='assetStatusId', to_field='id',
related_name='app_status')
recordownerid = models.ForeignKey(Tblusergroups, db_column='recordOwnerId', blank=True, null=True,
to_field='groupid', related_name='app_owner')
lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
# upsize_ts = models.TextField(blank=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'tblApplications'
class Tbldatabases(models.Model):
dbid = models.AutoField(db_column='dbId', primary_key=True)
dbname = models.CharField(db_column='dbName', max_length=255)
serverid = models.ForeignKey('Tblservers', db_column='serverId', to_field='serverid', related_name='db_serv')
servicename = models.CharField(db_column='serviceName', max_length=255, blank=True)
dbtypeid = models.IntegerField(db_column='dbTypeId', blank=True, null=True)
inceptiondate = models.DateTimeField(db_column='inceptionDate', blank=True, null=True)
comments = models.TextField(blank=True)
assetstatusid = models.IntegerField(db_column='assetStatusId')
recordownerid = models.IntegerField(db_column='recordOwnerId', blank=True, null=True)
lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
# upsize_ts = models.TextField(blank=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'tblDatabases'
class Tbldomaincodes(models.Model):
id = models.IntegerField(db_column='ID', primary_key=True)
domain = models.CharField(primary_key=True, max_length=255)
displayname = models.CharField(db_column='displayName', primary_key=True, max_length=255)
displayorder = models.IntegerField(db_column='displayOrder', blank=True, null=True)
comments = models.TextField(blank=True)
lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
# upsize_ts = models.TextField(blank=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'tblDomainCodes'
Extend your filter set and reference the field in the other model:
class TblapplicationsFilter(django_filters.FilterSet):
name = django_filters.CharFilter(name="applicationname", lookup_type="exact")
env = django_filters.CharFilter(name="environmentid__name")
# ^^^^^^^^^^^^^^^^^^^
class Meta:
model = Tblapplications
fields = ['applicationname', 'name', 'env']
Also, you may wish to name your ForeignKey fields without the id suffix, which is the Django convention. In Django, when you access Tblapplications.environmentid, it is normally a model instance, not the actual id integer itself.

django model reduce duplicate code

Here is my django model
Because I have ProjectsArchive and StatusArchive for saving history datas
You can see many fields are duplicate
I wonder how to reduce the duplicate code to make the code simple
class Projects(models.Model):
title = models.CharField(max_length=255, blank=True)
link = models.CharField(max_length=300, blank=True)
state = models.CharField(max_length=30, blank=True)
update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
....
class ProjectsArchive(models.Model):
title = models.CharField(max_length=255, blank=True)
link = models.CharField(max_length=300, blank=True)
state = models.CharField(max_length=30, blank=True)
update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
....
class Status(models.Model):
project = models.ForeignKey(Projects, null = True, blank = True)
state = models.CharField(max_length=255, blank=True)
crawl_update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
....
class StatusArchive(models.Model):
project = models.ForeignKey(ProjectsArchive, null = True, blank = True)
state = models.CharField(max_length=255, blank=True)
crawl_update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
....
You can refer here: Abstract base classes
According to your question, I will do:
class BasicInfo(models.Model):
title = models.CharField(max_length=255, blank=True)
link = models.CharField(max_length=300, blank=True)
state = models.CharField(max_length=30, blank=True)
update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
class Meta:
abstract = True
class Projects(BasicInfo):
....
class ProjectsArchive(BasicInfo):
....
After completing BasicInfo, You can reuse the title, link , state and update_at.
However we can create common model containing state and crawl_update_at for Status and StatusArchive.
class StatusInfo(models.Model):
state = models.CharField(max_length=255, blank=True)
crawl_update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
class Meta:
abstract = True
class Status(StatusInfo):
project = models.ForeignKey(Projects, null = True, blank = True)
....
class StatusArchive(StatusInfo):
project = models.ForeignKey(ProjectsArchive, null = True, blank = True)
...
You can create a CommonModel where in you can put your redundant fields then whichever models you want to use them in just inherit CommonModel instead of models.Model.
class CommonModel(models.Model):
class Meta:
abstract = True
title = models.CharField(max_length=255, blank=True)
link = models.CharField(max_length=300, blank=True)
state = models.CharField(max_length=30, blank=True)
update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
class ProjectArchive(CommonModel):
any_new_field_you_want_to_add
What you are looking for is abstract meta class.
https://docs.djangoproject.com/en/1.8/topics/db/models/
class ProjectTemplate(models.Model):
title = models.CharField(max_length=255, blank=True)
link = models.CharField(max_length=300, blank=True)
state = models.CharField(max_length=30, blank=True)
update_at = models.DateTimeField(auto_now=True, blank=True, null=True)
....
class Meta:
abstract = True
class Projects(ProjectTemplate):
pass
class ProjectsArchive(ProjectTemplate):
pass
You could use inheritance.
Please look at the following link
django abstract models versus regular inheritance
And also this the django docs about models (take a look at Abstract base classes)
https://docs.djangoproject.com/en/1.8/topics/db/models/

Django model query

I have question about Django query models. I know how to write simple query, but Im not familiar with LEFT JOIN on two tables. So can you give me some advice on his query for better understanding DJango ORM.
query
select
count(ips.category_id_id) as how_many,
ic.name
from
izibizi_category ic
left join
izibizi_product_service ips
on
ips.category_id_id = ic.id
where ic.type_id_id = 1
group by ic.name, ips.category_id_id
From this query I get results:
How many | name
0;"fghjjh"
0;"Papir"
0;"asdasdas"
0;"hhhh"
0;"Boljka"
0;"ako"
0;"asd"
0;"Čokoladne pahuljice"
0;"Mobitel"
2;"Čokolada"
And I have also try with his Django query:
a = Category.objects.all().annotate(Count('id__category',distinct=True)).filter(type_id=1)
But no results.
My models:
models.py
class Category(models.Model):
id = models.AutoField(primary_key=True)
type_id = models.ForeignKey('CategoryType')
name = models.CharField(max_length=255)
def __str__(self):
return str(self.name)
class Product_service(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, blank=True, null=True)
selling_price = models.DecimalField(decimal_places=5, max_digits=255, blank=True, null=True)
purchase_price = models.DecimalField(decimal_places=5, max_digits=255, blank=True, null=True)
description = models.CharField(max_length=255, blank=True, null=True)
image = models.FileField(upload_to="/", blank=True, null=True)
product_code = models.CharField(max_length=255, blank=True, null=True)
product_code_supplier = models.CharField(max_length=255, blank=True, null=True)
product_code_buyer = models.CharField(max_length=255, blank=True, null=True)
min_unit_state = models.CharField(max_length=255, blank=True, null=True)
state = models.CharField(max_length=255, blank=True, null=True)
vat_id = models.ForeignKey('VatRate')
unit_id = models.ForeignKey('Units')
category_id = models.ForeignKey('Category')
If you culd help me on this problem.
You should add a related name on the category_id field like:
category_id = models.ForeignKey('Category', related_name="product_services")
so that in your query you can do:
a = Category.objects.all().annotate(Count('product_services',distinct=True)).filter(type_id=1)
and then you can access the individual counts as:
a[0].product_services__count

Categories