I have two models in Django: one of them is a bunch of entries, and another model is a link table - it basically maps one entry to another, so it has a entry_a_id and an entry_b_id field... how do I write a QuerySet query to properly select the first entry's related fields then the second one?
=== EDIT ===
Here's an example:
class Nodes(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=45)
description = models.CharField(max_length=255)
class Links(models.Model):
id = models.AutoField(primary_key=True)
node_a_id = models.ForeignKey('Nodes')
node_b_id = models.ForeignKey('Nodes')
So, with that said (or typed), I would like to be able to figure out how to have a final result of node_a_id, name, description, node_b_id, name, description according to the Links model. Let me know if you want me to clarify further.
I might have misunderstood but here I go. Having a Link object:
>>> link = Links.objects.all()[0]
You automagically have access to the fields of your foreign relations (node_a_id and node_b_id). With that, you can do the following:
>>> link = Links.objects.all()[0]
>>> link.node_a_id.id
1
>>> link.node_a_id.name
'Name for node A'
>>> link.node_a_id.description
'Description for node B'
>>> link.node_b_id.id
2
>>> link.node_b_id.name
'Name for node B'
>>> link.node_b_id.description
'Description for node B'
As a side note, there is no point in using id as your auto-incrementing primary key field since you get that for free: AutoField and Automatic primary key fields
Related
Model:
class List(models.Model):
Lid = models.AutoField(primary_key=True)
Name = models.CharField(max_length=100)
addr1 = models.CharField(max_length=100)
addr2 = models.CharField(max_length=100)
City = models.CharField(max_length=40)
State = models.ForeignKey(State,blank=True, on_delete=models.DO_NOTHING, default=None,to_field="state",db_column="State") #,to_field="state",db_column="State"
Below is the error appears when tried to migrate,
IntegrityError(
django.db.utils.IntegrityError: The row in table 'list' with primary key '1' has an invalid foreign key: list.State contains a value '' that does not have a corresponding value in State.state.
How to fix this issue? I did add those 'blank=True' and on_delete=models.DO_NOTHING after searching for a solution in google, still no luck.
If you want have row from List and 1 row from State.
It can be o2o-key (don't matter which model), or you can use Foreign-key in List.
But: DB-Table State should have in your db_column="State" only unique keys.
If you want to have every row from List and some rows from State.
Foreign key should be in State model, not in List.
After that: On migration you should convert column list.state to value_type like in state.state.
For example you have type(list.state) = string and type(State.state) = integer. It can works without it, i know, but it is better to check it on migration.
if you have in list.state default=None, also you can convert every_list_row.state = '' to every_list_row.state = None, to avoid problem in future, on export etc.
If you receive ForeignObjectException - object not exists on list_row.state:
You can create something like that:
#property
def get_state(self):
return hasattr(list_row, 'state') and list_row.state or ''
and after that: list_row.get_state
I got a ValueError while trying to add model instances with a many-to-many relationship.
ValueError: "(Idea: hey)" needs to have a value for field "id" before this many-to-many relationship can be used.
A lot of responses were given here, but none was helpful.My (idea) solution was to "manually" input the "id" values.
>>> import django
>>> django.setup()
>>> from myapp1.models import Category, Idea
# Notice that I manually add an "id"
>>> id2=Idea.objects.create(
... title_en='tre',
... subtitle_en='ca',
... description_en='mata',
... id=5,
... is_original=True,
... )
>>> id2.save()
>>> cat22=Category(title_en='yo')
>>> cat22.save()
>>> id2.categories.add(cat22)
>>> Idea.objects.all()
<QuerySet [<Idea: tre>]>
>>> exit()
How do i command django to auto-add the "id" field?
Note: I tried adding autoField but failed, thanks
#python_2_unicode_compatible
class Idea(UrlMixin, CreationModificationDateMixin, MetaTagsMixin):
id = models.IntegerField(primary_key=True,)
title = MultilingualCharField(_("Title"), max_length=200,)
subtitle = MultilingualCharField(_("Subtitle"), max_length=200, blank=True,)
description = MultilingualTextField(_("Description"), blank=True,)
is_original = models.BooleanField(_("Original"), default=False,)
categories = models.ManyToManyField(Category,
You're confusing two things here:
With many-to-many relationships, when connecting two objects, both objects must already be saved to the database (have a primary key), because under the hoods, Django creates a third object that points at the two objects to connect them. It can only do that if both have an id, assuming id is the primary key.
When creating an object, you don't have to explicitly set the id (actually you shouldn't). By default, a django Model will have id set as an auto field and as a primary key (you can override that by specifying your own pk, but in general there's no need to). The id is automatically created when the model is saved the first time.
You saw the error because probably one of the objects (idea or category) wasn't saved to the database before you connected them. In your code sample, you don't have to pass id=5, it will work without it, because you save id2 and category before connecting them.
class Foo(models.Model):
name = models.CharField(max_length=20)
bar = models.ForeignKey(Branch, null=True)
class Bar(models.Model):
name = models.CharField(max_length=20)
When I do:
x = Foo.objects.get(bar_id=2)
I get:
*** FieldError: Cannot resolve keyword 'bar_id' into field. Choices are: bar, id, name
Shouldn't bar_id use the foreign key id directly to look for the matching Foo?
I understand I can query the db first to get the Bar object and then use it in the get statement, but should I waste a query on this if the id is already in the Foo table?
(I'm using an old django and python for a legacy project: django 1.4 python 2.7.2)
It's x = Foo.objects.get(bar__id=2) with double underscore.
django doc.
x = Foo.objects.get(bar__id=2)
Even though the SQL table is using bar_id as the name of the column for the ForeignKey, you need to use bar__id to traverse the FK.
Hopefully, Django will optimize this and don't do a real join to execute the query:
>>> print MyModel.objects.filter(bar__id=1).values('pk').query
SELECT "myapp_mymodel"."id" FROM "myapp_bar" WHERE "myapp_mymodel"."bar_id" = 1
# Let's compare this with a real joining... (assuming Bar has a `name` field)
>>> print MyModel.objects.filter(bar__name='Thing').values('pk').query
SELECT "myapp_mymodel"."id" FROM "myapp_bar" INNER JOIN "myapp_bar" ON (
"myapp_mymodel"."bar_id" = "myapp_bar"."id"
) WHERE "myapp_bar"."name" = Thing
How can I order a model with respect to a foreign key's column without joining in the foreign key table?
For example, if I have:
class WidgetType(Model):
id = AutoField(primary_key=True)
label = CharField(max_length=16)
class Meta:
ordering = ["label"]
class Widget(Model):
type = ForeignKey(WidgetType)
How can I generate the query:
SELECT * FROM widgets_widget ORDER BY type_id
Without joining in the foreign key table?
It seems like the <fk>_id can't be used:
>>> Widget.objects.all().order_by("type_id")
FieldError: Cannot resolve keyword 'type_id' into field. Choices are: type
Using <fk>__id seems to join in, and then ignore, the FK table:
>>> print Widget.objects.all().order_by("type").query
SELECT * FROM widgets_widget
LEFT OUTER JOIN widgets_widgettype ON …
ORDER BY widgets_widget.type_id
And using <fk> uses the foreign key model's default ordering:
>>> print Widget.objects.all().order_by("type").query
SELECT * FROM widgets_widget
LEFT OUTER JOIN widgets_widgettype ON …
ORDER BY widgets_widgettype.label
If you're using Django 1.7, please refer to Geo Jacob's answer - it's included.
If not, and if you don't need object instances, you could help yourself with values():
class UserProfile(models.Model):
user = models.OneToOneField(User)
country = models.CharField(max_length=255)
>>> qs = UserProfile.objects.all().values('user', 'country').order_by('user')
>>> print qs.query
SELECT `userprofiles_userprofile`.`user_id`, `userprofiles_userprofile`.`country` FROM `userprofiles_userprofile` ORDER BY `userprofiles_userprofile`.`user_id` ASC
>>> qs
[{'country': u'AT', 'user': 1L}, {'country': u'AT', 'user': 18L}, {'country': u'RU', 'user': 19L}, [...]
So I have a model MyModel with a ForeignKey field fkfield. And i need to do something like this (simplified):
MyModel.objects.values_list('id', 'fkfield').order_by('fkfield')
For example I want to groupby them further by fkfield so I need my objects to be sorted by this field. And the only thing I will use later is fkfield_id. I mean I dont need any data from related model.
But django performs a join sql query (as described in docs) and uses related model's ordering. The same happens if i explicitly try to order by id:
MyModel.objects.values_list('id', 'fkfield').order_by('fkfield__id')
and I get:
SELECT `mymodel`.`id`,
`mymodel`.`fkfield_id`
FROM `mymodel`
LEFT OUTER JOIN `related_table`
ON ( `mymodel`.`fkfield_id` = `related_table`.`id` )
ORDER BY
`related_table`.`id` ASC
What i really expect is:
SELECT `id`,
`fkfield_id`
FROM `mymodel`
ORDER BY
`fkfield_id` ASC
But I can't find a way to do it. .order_by('fkfield_id') raises exception that says that there is no such a field.
I managed to get things work using extra but I can't understand why such a simple and obvious behaviour can't be used without hacks. Or maybe i missed smth?
UPDATE: models.py
class Producer(models.Model):
name = models.CharField(max_length=100)
class Meta:
ordering = ('name',)
class Collection(models.Model):
name = models.CharField(max_length=100)
producer = models.ForeignKey('Producer')
class Meta:
ordering = ('name',)
print Collection.objects.values_list('producer', 'id').order_by('producer').query
>>> SELECT `catalog_collection`.`producer_id`, `catalog_collection`.`id`
>>> FROM `catalog_collection`
>>> INNER JOIN `catalog_producer` ON
>>> (`catalog_collection`.`producer_id` = `catalog_producer`.`id`)
>>> ORDER BY `catalog_producer`.`name` ASC
Try
.order_by('fkfield')
My query is
Post.objects.values('author', 'id').order_by('author')
as sql:
SELECT "blogs_post"."author_id",
"blogs_post"."id"
FROM "blogs_post"
ORDER BY "blogs_post"."author_id" ASC
UPDATE
Kind of messy solution:
MyModel.objects.extra(select={'fkfield_id': 'fkfield_id'})\
.values_list('id', 'fkfield_id')\
.order_by('fkfield_id')