I used python manage.py inspectdb > models.py to create models from my old SQL database. Workout.user_id is a foreign key to users table, but inspectdb lost this linking by making it just models.IntegerField().
Database looks like this:
Users
+----+------------+
| id | name |
+----+------------+
| 1 | Bob |
| 2 | Alice |
| 3 | Tom |
+----+------------+
Workout
+---------+------------+------------+
| user_id | workout_id | date |
+---------+------------+------------+
| 2 | 1 | 2021-02-18 |
| 2 | 2 | 2021-02-20 |
| 3 | 3 | 2021-02-21 |
+---------+------------+------------+
And models.py comes out like this:
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
# * Rearrange models' order
# * Make sure each model has one field with primary_key=True
# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from django.db import models
class Users(models.Model):
id = models.AutoField(primary_key=True)
name = models.TextField(blank=True, null=True)
class Meta:
managed = False
db_table = 'users'
class Workout(models.Model):
user_id = models.IntegerField()
workout_id = models.AutoField(primary_key=True)
date = models.DateField(blank=True, null=True)
class Meta:
managed = False
db_table = 'workout'
Workout.user_id is a foreign key to users table, but inspectdb lost this linking by making it just models.IntegerField().
I tried setting ForeignKey like this:
user_id = models.ForeignKey('Users', on_delete=models.CASCADE)
but it gives an error:
django.db.utils.OperationalError: (1054, "Unknown column 'workout.user_id_id' in 'field list'")
Can this kind of ForeignKey linking be achieved or how should I proceed?
Django automatically adds _id to the ForeignKey for the name of the table column, you thus name it user. You can also specify with the db_column=… parameter [Django-doc] the name of the database column, although that is not necessary here:
class Workout(models.Model):
user = models.ForeignKey(
'Users',
db_column='user_id'
)
workout_id = models.AutoField(primary_key=True)
date = models.DateField(blank=True, null=True)
class Meta:
managed = False
db_table = 'workout'
Related
I've a model with different fields.
I. E.
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
DB i.E.
id | first_name | Last_name | Instrument
1 | Stefan | Oslay | Bass
2 | Richard | Wagner | Klavier
Than I have a second model. I want to reference with foreign key the Musician. And then i want also a new custom field which contains also a attribut from Musician.
class MusikWerk(models.Model):
Interpret = models.ForeignKey(Musician, on_delete=models.CASCADE, null=FALSE, blank=False)
Title = models.CharField(max_length=50)
def instrument_wert(self)
return '%s '%(self.instrument)
instrument = instrument_wert(Musician)
DB i.E.
id | Interpretid | Title | Instrument
1 | 2 | TitelWagner | Klavier
But with my code i don't create the column Instrument in database and can't save the foreign field in them 😦
I'm trying to write the following raw query with the ORM. I'm not sure is it possible or not.
select first_name,
middle_name,
COALESCE(middle_name, (
select middle_name
from contacts c2
where c2.first_name = c1.first_name
and c2.last_name = c1.last_name
and c2.middle_name is not null
order by length(c2.middle_name) desc
limit 1
)
) expected,
last_name
from contacts c1
The expected result is like the following, if middle_name is null, get the middle name from another record that has the same first_name and last_name.
id| first_name | middle_name | expected | last_name
1 | ahmet | <NULL> | burak | ozyurt
2 | ahmet | burak | burak | ozyurt
class Contact(models.Model):
first_name = models.CharField(max_length=250)
last_name = models.CharField(max_length=250, null=True, blank=True)
middle_name = models.CharField(max_length=250, null=True, blank=True)
DB: Postgres
Django Version: 3.12
By using the django ORM, you can perform the same query by using the following code
from django.db import models
from django.db.models.functions import Coalesce, Length
matched_middle_name_queryset = Contact.objects.filter(
first_name=models.OuterRef("first_name"),
last_name=models.OuterRef("last_name"),
middle_name__isnull=False,
).annotate(
middle_name_len=Length("middle_name")
).order_by("-middle_name_len").values("middle_name")[:1]
result = Contact.objects.annotate(
matched_middle_name=models.Subquery(matched_middle_name_queryset)
expected=Coalesce(
models.F("middle_name")
models.F("matched_middle_name"),
).values("id", "first_name", "middle_name", "expected", "last_name")
)
Explanations
models.OuterRef is used for referring to the field from the parent query of a subquery.
- prefix in the order_by("-middle_name_len") is for descending order
.values("middle_name") is for selecting only middle_name values.
the slicing [:1] is for limiting the result from the subquery to be one.
Tips
You can use result.query to inspect what query the ORM will generate for you.
I'm pretty new to django and the admin module. I'm looking for a way to add on a admin class
some fields that i query through a reverse relationship.
I can currently retrieve the interesting fields and put them in one column thanks to a specific function
using list_diplay, but i cannot manage to create a list_display field BY returned query object:
as example, now I get as column:
|Inventory_id| Mousqueton1 |
| 22 | foo1,foo2 |
and i would like to have this kind of output, to easily create filters:
|Inventory_id| Mousqueton1 | Mousqueton2 |
| 22 | foo1 | foo2 |
Here's my current models.py
class Kit(models.Model):
inventory_id = models.CharField(max_length=20,unique=True)
description = models.TextField(null=True)
creation_date = models.DateField(auto_now_add=True)
last_update = models.DateTimeField(auto_now=True)
class Mousquetons(models.Model):
inventory_id = models.CharField(max_length=20,unique=True)
serial = models.IntegerField(unique=False)
description = models.TextField(null=True)
creation_date = models.DateField(auto_now_add=True)
last_update = models.DateTimeField(auto_now=True)
kit = models.ForeignKey(Kit,on_delete=models.PROTECT,null=True)
and admin.py
#admin.register(Kit)
class KitAdmin(admin.ModelAdmin):
list_display= ['inventory_id','m']
def get_queryset(self, obj):
qs = super(KitAdmin, self).get_queryset(obj)
return qs.prefetch_related('mousquetons_set')
def m(self, obj):
return list(obj.mousquetons_set.all())
Maybe my data modeling is not the right way to perform this kind of operation, Any advice would be great.
Thanks !
When creating a model object, can you use the verbose name to create? I have a model that has a dot in the name and I cannot have dot in a variable name.
file.xls
|---------|-----------------------|
| Start | ExonicFunc.UHNCLGGene |
|---------|-----------------------|
| 2488153 | nonsynonymous SNV |
| 3301721 | synonymous SNV |
|---------|-----------------------|
models.py
class Variant(models.Model):
start = models.CharField(max_length=10, null=True)
exonic_function = models.CharField(verbose_name="ExonicFunc.UHNCLGGene", max_length=20, null=True)
view.py
def upload(request):
# reads file.xls
raw_data = pandas.read_excel(request.FILES.get("file"))
for _, row in raw_data.iterrows():
variant = Variant.objects.create(**row)
verbose_name is just a label for your field in admin panel. You probably want to use db_column
exonic_function = models.CharField(db_column="ExonicFunc.UHNCLGGene", max_length=20, null=True)
and they assign value in your view as usual
variant.exonic_function = "bla"
I'm using django-tables and trying to display a table containing some related fields.
class User(models.Model):
name = models.CharField(_("name"), max_length=100)
comp = models.ForeignKey(Company)
class Company(models.Model):
name = models.CharField(_("name"), max_length=100)
country = models.CharField(_("country"), max_length=200)
def __unicode__(self):
return self.name
class UserTable(tables.Table):
class Meta:
model = User
fields = ('name', 'comp', 'comp.country',)
empty_text = _('No user')
I get the correct data but Comp in each related heading
+------+----------------+-----------------+
| Name | Comp | Comp |
+------+----------------+-----------------+
| Bob | Comp 1 | France |
| John | Comp 2 | United Kingdom |
| ... | ... | ... |
+------+----------------+-----------------+
What could be the reason ?
Shouldn't I get Name, Comp, Country ?
Update
Mistake on the original question, I have updated it.
Using accessor to resolve your fields allows to define the verbose names
class UserTable(tables.Table):
name = tables.Column(accessor='name', verbose_name=_('name'))
comp = tables.Column(accessor='comp', verbose_name=_('company'))
country = tables.Column(accessor='comp.country', verbose_name=_('country'))
From django-table docs -
fields – specify model fields to include
But you're including relationships -
fields = ('user', 'user.pref.country', 'user.pref.phone',)
I never used that app, so I'm not sure how it's working, but I think it's taking the verbose name of each field, in later two cases, user field comes first, hence it's taking user fields' verbose name.
Update:
It seems you can provide custom verbose names, try this. Not sure if this will work, as Country is a related field. -
class UserTable(tables.Table):
country = tables.Column(verbose_name="Country")
class Meta:
model = User
fields = ('name', 'comp', 'comp.country',)
empty_text = _('No user')