In Rails, and in symfony with Doctrine, you can save a record and then you'll have the record's id. For example:
b = Bank.new
b.save
#b.id now has a value
But in Django that's apparently not how it works:
>>> b = Bank()
>>> b.name = "Fred's Bank"
>>> b.identifier = "fred"
>>> b.save()
>>> b.id
>>> b.id.__class__
<type 'NoneType'>
>>>
As you can see, b.id evaluates to nothing. Do I have to go back and select the id if I want it? That would be a pain in the ass, especially for tables that have a lot of columns.
That is how it works in Django. Assuming that Bank is a Django model, it does get an ID on save, and the current instance reflects that. I can't imagine what you have done to break that. You'll need to post the code of the Bank model.
Related
I have a list of objects and a model includes ManyToManyField of this object.
I'd like to get objects who have the same list of objects in this field.
that's means __in won't work because he will do OR between the objects in the list and not AND.
I was trying using the AND Q Lookup, but it didn't work (after checking the .query text, it seems that he doing the AND inside the field object, instead of the object itself, so obviously the field object id don't have two different ids..)
here's the interceptor I played with
results_query_set[0]
<Results: Results object (2)>
results_query_set[0].users.all()
<QuerySet [<User: test_user>, <User: test_user_2>]>
users
[<User: test_user>, <User: test_user_2>]
users_q
<Q: (AND: ('users', <User: test_user>), ('users', <User: test_user_2>))>
results_query_set.filter(users=users[0])
<QuerySet [<Results: Results object (2)>]>
results_query_set.filter(users=users[1])
<QuerySet [<Results: Results object (2)>]>
results_query_set.filter(users_q)
<QuerySet []>
results_query_set.filter(Q(users=users[0]) & Q(users=users[1]))
<QuerySet []>
and the result results_query_set.filter(users_q).query.__str__() reproduce is
'SELECT "results_table"."id", "results_table"."date", "results_table"."lookup", "results_table"."value" FROM "results_table" INNER JOIN "results_table_users" ON ("results_table"."id" = "results_table_users"."widgetresults_id") WHERE ("results_table_users"."user_id" = 1 AND "results_table_users"."user_id" = 2)
I can chain .filter for each user, but of course, I'd like to make one query instead of queries by the numbers of my input.
You need to JOIN the target table (User in your case) multiple times (for every single user) in order to build such a query.
The way to do this in Django is by calling .filter multiple times.
users = [user1, user2] # a list of users your are interested to filter on
initial_qs = Results.objects.all() # or whatever your results_query_set is
result_qs = reduce(lambda qs, user: qs.filter(users=user.id), users, initial_qs)
# At this point you will have results containing user1 and user2
# but this also includes results with more users (e.g. users 1, 2 and 3)
# if you want to exclude those, you need to filter by the total users count too
result_qs = result_qs.annotate(cnt=models.Count('users')).filter(cnt=len(users))
I have not tried this, but I think you might be able to use postgresql's array_agg function. The Django implementation is here.
from django.contrib.postgres.aggregates import ArrayAgg
ideal_user_list = [] # some list.
# Or fetch it directly from the db using the below query and `get`
Results.objects.annotate(
related_user_array=ArrayAgg('users__id', ordering='users__id')
).filter(related_user_array=ideal_user_list)
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.
Here is my models.py:
class Foo(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=30)
In django manage.py shell:
>>> a,b = Foo.objects.get_or_create(name='hi')
>>> b
True
>>> vars(a)
{'_state': <django.db.models.base.ModelState object at 0x02761390>, 'id': None,
'name': 'hi'}
The problem here is the customized id attribute has no value. And if I continue to do the following:
>>> c = foo.objects.get(name='hi')
>>> c.id
1
>>> a is c
False
So that newly created object (denoted by c) already exists now, but b is not an exact reference to it like c is.
Is this a bug? My django version is 1.6.5.
By default, if you have not specified the id field for you model, Django will create AutoField:
id = models.AutoField(primary_key=True)
In your case you've created just IntegerField. I suppose this is the point. In the database, it will still be incremented, but django won't assign the id value from database to the object, returned by get_or_create
By the way, in your question:
>>> b is c
False
b - is a bool value. I think you were trying to do
>>> a is c
But also this is not a good idea. If you want to compare django model objects, use ==, not is:
>>> a == c
You will get False anyway, as a has its id set to None.
You have declared your id field as an IntegerField, so Django does not know it needs to autoincrement. You could define it as an AutoField, but actually there is no reason to declare it at all: Django will automatically define it for you if you leave it out.
Note this has nothing to do with get_or_create: you would have exactly the same problem with a normal create/save.
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
I have model form with several fields works as expected. Now I need, for specific reasons, to get form field in view but got error 'EditPostForm' object has no attribute 'about' when I call mydata1 = form.about in view. But about field exist of course. form.data.about also wont work etc. So how can I get it? Thanks.
If you form has instance associated to it, you can try
post = EditPost.objects.get(id=id)
form1 = EditPostForm(instance=post)
form1.instance.about
Based on your comment below if you are using ManyToMany relation you can get the value as
>>> bf = BookForm(instance=book)
>>> bf.instance.authors
<django.db.models.fields.related.ManyRelatedManager object at 0x0000000004658B38>
>>> bf.instance.authors.all() #which returns a query set of related objects
[<Author: Kotian>]
>>> bf.instance.authors.all()[0]
<Author: Kotian>
>>> bf.instance.authors.all()[0].name
u'Kotian'
or based on how you have defined the ManyToMany
>>> af = AuthorForm(instance=author)
>>> af.instance.name
u'MyName'
>>> af.instance.book_set
<django.db.models.fields.related.ManyRelatedManager object at 0x0000000004658C18>
>>> af.instance.book_set.all() # returns queryset
[<Book: Book object>, <Book: Book object>]
>>> af.instance.book_set.all()[0] #accessing first object here
<Book: Book object>
>>> af.instance.book_set.all()[0].name
u'Lepord'