Django reverse ForeignKey lookup returns None - django

I'm new to Django development and have just started writing an app.
I have two classes defined in models.py:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class NEO(models.Model):
name = models.CharField(max_length=100, default=' ')
sighter = models.ForeignKey(User, blank=True, null=True)
date_sighted = models.DateTimeField(default=timezone.now())
ratings = models.IntegerField(default=0)
#coords = models.ForeignKey('Coords', default='')
def __unicode__(self):
return self.name
class Coords(models.Model):
ra = models.FloatField('Right Ascension', default=0)
dec = models.FloatField('Declination', default=0)
neo = models.ForeignKey(NEO, related_name='neo_coords', null=True)
def __unicode__(self):
return str(self.ra) + ' ' + str(self.dec)
Each Coords object links to a single NEO and vice versa.
Uncommenting the Neo.Coords line and then calling n.Coords returns a None. Given a NEO object, how can I get the corresponding Coords object?

ForeignKey here is a ManyToOne relationship (as suggested in the docs), So in your case multiple Coords objects can be binded to a single NEO object. If you want a OneToOne Relation you may want to use models.OneToOneField (documentation here).
In case of foreign key's lookup you can use.
NEO.coords_set.get(**lookup_arguments_here)
# Here NEO.coords_set is the list of coords objects bound to this particular NEO object.
and in case of OneToOne you can simply use
NEO.coords

It doesn't make sense to have two tables referencing each other with dual foreign keys because you run into a chicken or the egg problem. You need to decide whether or not there can be a one-to-many relation or a one-to-one relation.
Can a NEO have multiple Coords? Can a Coord have multiple NEOs? If the answer is yes, then you need a ForeignKey. The ForeignKey should be on the many of the one-to-many side of the relation. If the answer was no, and there can only be a one-to-one link, then you want a OneToOneField.
To access the reverse side of the relationship it is simple:
# multiple coords per neo
class NEO(models.Model):
name = ...
class Coords(models.Model):
name = ...
neo = models.ForeignKey(NEO)
c = Coords.objects.get(id=1)
c.neo # shows the neo
n = NEO.objects.get(id=1)
coords = n.coords_set.all() # multiple coords per neo
If instead you had a one to one relationship:
class NEO(models.Model):
name = ...
class Coords(models.Model):
name = ...
neo = models.OneToOneField(NEO)
c = Coords.objects.get(id=1)
c.neo # shows the neo
n = NEO.objects.get(id=1)
coords = n.coords # only one possible coord per neo
https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships

Related

Django Foreign Key Aliasing

I'm trying to be able to alias a column name from a model's foreign key. I want to be able to change 'owner__username' to just 'username' when passing a JSON response.
query_n = Example.objects.values('owner__username','name')
print(query_n[0])
Which prints
{'name': 'e_adam', 'owner__username': 'adam'}
The only renaming of a column I have seen was via annotate() however, that isn't even truly a column (AVG, SUM, ...)
The Example model has a foreign key owner, which is 'auth.User' model.
Any thoughts?
I'm not too sure about this but if you are using django >= 1.7, sounds like you could use annotate to create alias for named arguments in values(). I found a related django ticket, to quote from the latest response:
Just quickly, with the changes to annotate that have landed, it is now
possible to create aliases yourself, and reference them from the
values call:
from django.db.models import F
Model.objects.annotate(my_alias=F('some__long__name__to__alias')) \
.values('my_alias')
aliasName = models.ForeignKey(modelName, to_field='fieldName', on_delete=models.CASCADE)
This is the format for aliasing in Django Foreign Key
Here is full Models page
from django.db import models
# Create your models here.
class Farm(models.Model):
srFarm = models.AutoField(primary_key=True)
name = models.CharField(max_length = 264, unique =True)
address = models.CharField(max_length = 264)
def __str__(self):
temp = '{0.name},{0.address}'
return temp.format(self)
class Batch(models.Model):
srBatch = models.AutoField(primary_key=True)
farmName = models.ForeignKey(Farm, to_field='name', on_delete=models.CASCADE)
def __str__(self):
temp = '{0.farmName}'
return temp.format(self)

Django date query from newest to oldest

I am building my first Django program from scratch and am running into troubles trying to print out items to the screen from newest to oldest.
My model has an auto date time field populated in the DB as so:
Model
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
from django.utils import timezone
class TaskItem(models.Model):
taskn = models.CharField(max_length = 400)
usern = models.ForeignKey(User)
#Created field will add a time-stamp to sort the tasks from recently added to oldest
created_date = models.DateTimeField('date created', default=timezone.now)
def __str__(self):
return self.taskn
What is the line of code that would be abel to sort or print this information in order from newest creation to oldest?
Want to implement it into this call:
taskitems2 = request.user.taskitem_set.all().latest()[:3]
ordered_tasks = TaskItem.objects.order_by('-created_date')
The order_by() method is used to order a queryset. It takes one argument, the attribute by which the queryset will be ordered. Prefixing this key with a - sorts in reverse order.
By the way you also have Django's created_at field at your disposal:
ordered_tasks = TaskItem.objects.order_by('-created_at')
You can set your ordering in model Meta class. This will be the default ordering for the object,for use when obtaining lists of objects.
class TestModel(models.Model):
...
created_at = models.DateField()
....
class Meta:
ordering = ['-created_at']
Or you can apply ordering to specific queryset.
TestModel.objects.order_by('-created_at')

What's the difference between django OneToOneField and ForeignKey?

What's the difference between Django OneToOneField and ForeignKey?
Differences between OneToOneField(SomeModel) and ForeignKey(SomeModel, unique=True) as stated in The Definitive Guide to Django:
OneToOneField
A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the "reverse" side of the relation will directly return a single object.
In contrast to the OneToOneField "reverse" relation, a ForeignKey "reverse" relation returns a QuerySet.
Example
For example, if we have the following two models (full model code below):
Car model uses OneToOneField(Engine)
Car2 model uses ForeignKey(Engine2, unique=True)
From within python manage.py shell execute the following:
OneToOneField Example
>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>
ForeignKey with unique=True Example
>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all()
[<Car2: Mazda>]
Model Code
from django.db import models
class Engine(models.Model):
name = models.CharField(max_length=25)
def __unicode__(self):
return self.name
class Car(models.Model):
name = models.CharField(max_length=25)
engine = models.OneToOneField(Engine)
def __unicode__(self):
return self.name
class Engine2(models.Model):
name = models.CharField(max_length=25)
def __unicode__(self):
return self.name
class Car2(models.Model):
name = models.CharField(max_length=25)
engine = models.ForeignKey(Engine2, unique=True, on_delete=models.CASCADE)
def __unicode__(self):
return self.name
A ForeignKey is a many-to-one relationship. So, a Car object might have many instances of Wheel. Each Wheel would consequently have a ForeignKey to the Car it belongs to. A OneToOneField would be like an instance of Engine, where a Car object has at most one and only one.
The best and the most effective way to learn new things is to see and study real world practical examples. Suppose for a moment that you want to build a blog in django where reporters can write and publish news articles. The owner of the online newspaper wants to allow each of his reporters to publish as many articles as they want, but does not want different reporters to work on the same article. This means that when readers go and read an article they will se only one author in the article.
For example: Article by John, Article by Harry, Article by Rick. You can not have Article by Harry & Rick because the boss does not want two or more authors to work on the same article.
How can we solve this 'problem' with the help of django? The key to the solution of this problem is the django ForeignKey.
The following is the full code which can be used to implement the idea of our boss.
from django.db import models
# Create your models here.
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
def __unicode__(self):
return self.first_name
class Article(models.Model):
title = models.CharField(max_length=100)
reporter = models.ForeignKey(Reporter)
def __unicode__(self):
return self.title
Run python manage.py syncdb to execute the sql code and build the tables for your app in your database. Then use python manage.py shell to open a python shell.
Create the Reporter object R1.
In [49]: from thepub.models import Reporter, Article
In [50]: R1 = Reporter(first_name='Rick')
In [51]: R1.save()
Create the Article object A1.
In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)
In [6]: A1.save()
Then use the following piece of code to get the name of the reporter.
In [8]: A1.reporter.first_name
Out[8]: 'Rick'
Now create the Reporter object R2 by running the following python code.
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
Now try to add R2 to the Article object A1.
In [13]: A1.reporter.add(R2)
It does not work and you will get an AttributeError saying 'Reporter' object has no attribute 'add'.
As you can see an Article object can not be related to more than one Reporter object.
What about R1? Can we attach more than one Article objects to it?
In [14]: A2 = Article.objects.create(title='Python News', reporter=R1)
In [15]: R1.article_set.all()
Out[15]: [<Article: Python News>, <Article: TDD In Django>]
This practical example shows us that django ForeignKey is used to define many-to-one relationships.
OneToOneField is used to create one-to-one relationships.
We can use reporter = models.OneToOneField(Reporter) in the above models.py file but it is not going to be useful in our example as an author will not be able to post more than one article.
Each time you want to post a new article you will have to create a new Reporter object. This is time consuming, isn't it?
I highly recommend to try the example with the OneToOneField and realize the difference. I am pretty sure that after this example you will completly know the difference between django OneToOneField and django ForeignKey.
OneToOneField (one-to-one) realizes, in object orientation, the notion of composition, while ForeignKey (one-to-many) relates to agregation.
Also OneToOneField is useful to be used as primary key to avoid key duplication. One may do not have implicit / explicit autofield
models.AutoField(primary_key=True)
but use OneToOneField as primary key instead (imagine UserProfile model for example):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
When you access a OneToOneField you get the value of the field you queried. In this example a book model's 'title' field is a OneToOneField:
>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'
When you access a ForeignKey you get the related model object, which you can then preform further queries against. In this example the same book model's 'publisher' field is a ForeignKey (correlating to the Publisher class model definition):
>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'
With ForeignKey fields queries work the other way too, but they're slightly different due to the non-symmetrical nature of the relationship.
>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]
Behind the scenes, book_set is just a QuerySet and can be filtered and sliced like any other QuerySet. The attribute name book_set is generated by appending the lower case model name to _set.
I have also been confused with the usage of both the fields.
Let me give an example for understanding their usage, as I have faced the problem recently and realised the usage of both the fields.
I had a model, like this-
from django.contrib.auth.models import User
from django.db import models
class Attendance(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, default="", null=True)
date = models.CharField(max_length=11)
def __int__(self):
return self.id
Now the problem with this was that I can't make multiple objects with the same user,
i.e. a same user will have attendance on multiple days. Hence, multiple objects with same user.
But the OneToOne field didn't let me do that.
Image for reference
So, I changed my model to-
from django.contrib.auth.models import User
from django.db import models
class Attendance(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default="", null=True)
date = models.CharField(max_length=11)
def __int__(self):
return self.id
Now it works fine and I can mark attendance for a user on multiple days.
So that's where the difference is, OneToOne field will not allow you to make multiple objects with the same user(as an example) but with ForeignKey it is possible.
OneToOneField: if second table is related with
table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')
table2 will contains only one record corresponding to table1's pk value, i.e table2_col1 will have unique value equal to pk of table
table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')
table2 may contains more than one record corresponding to table1's pk value.
The easiest way to draw a relationship between items is by understanding them in plain languages. Example
A user can have many cars but then a car can have just one owner. After establishing this, the foreign key should be used on the item with the many relationship. In this case the car. Meaning you'll include user as a foreign key in cars
And a one on one relationship is quite simple. Say a man and a heart. A man has only one heart and a heart can belong to just one man
OneToOneField (Example: one car has one owner)
ForeignKey(OneToMany) (Example: one restaurant has many items)
ForeignKey allows you receive subclasses is it definition of another class but OneToOneFields cannot do this and it is not attachable to multiple variables

Modelling a relationship to a meta-table with 2 primary keys

I am very new to Django and would appreciate your help with this problem:
I have a table with meta-informationen (like the number of clicks, votes, comments ...) for different areas of my website (news, events in the calendar, films ..). The table is referenced by two primary keys (fi = INTEGER and tbl = CHAR).
class News(models.Model):
title = models.CharField()
...
class Film(models.Model):
title = models.Charfield()
...
class Calendar(models.Model):
title = models.Charfield()
...
class MetaInfo(models.Model):
fi = ForeignKey(??) # Integer
tbl = ForeignKey(??) # CharField
Example: fi = 1 and tbl = 'news' would relate to news-entry with primary key 1. And fi = 100, tbl = 'film' would relate to film-entry with primary key 100.
How to implment this? Is this even possible with django?
Django has a built-in feature called Generic Foreign Keys that allow you to tie a single table to multiple models in this fashion.
This is how you would create your models:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class News(models.Model):
title = models.CharField()
...
class Film(models.Model):
title = models.Charfield()
...
class Calendar(models.Model):
title = models.Charfield()
...
class MetaInfo(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
If you wish, you can be more explicit about the relationship between a model and MetaInfo by using GenericRelation. For example:
class Film(models.Model):
title = models.CharField()
metainfo = generic.GenericRelation('MetaInfo')
...
This allows you to access the related MetaInfo records directly from the Film model, as in
f = Film.objects.get(pk=1)
for mi in f.metainfo.all():
#mi is a matching MetaInfo record for Film record with pk=1
Just to elaborate a bit:
In the MetaInfo model, content_type serves as the equivalent of your tbl column (although it points to a Django construct called a ContentType; Django constructs one for each model in the app/set of apps) and object_id corresponds to your fi key. You actually generally don't pay much attention to those fields. Instead, you get and set the content object, which is the corresponding record. For example, instead of storing or retrieving tlb='Film', fi=1, you'd get or set content_object which corresponds directly to the Film record matching pk=1.
In essence, contenttype__name='Film', object_id=1 while content_object=Film.object.get(pk=1)
This is all assuming that this database is for Django use only. If it's an existing database that you're trying to use within Django, there isn't a straightforward way to handle this that I'm aware of.

Django: foreign key queries

I'm learning Django and trying to get the hang of querying foreign keys across a bridging table. Apologies if this is a duplicate, I haven't been able to find the answer by searching. I've got models defined as follows
class Place(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
class PlaceRef(models.Model):
place = models.ForeignKey(Place) # many-to-one field
entry = models.ForeignKey(Entry) # many-to-one field
class Entry(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=10)
If I want to retrieve all the Entries associated with a particular Place, how do I do it?
place = get_object_or_404(Place, id=id)
placerefs = PlaceRef.objects.filter(place=place)
entries = Entry.objects.filter(id.....)
Also, if there is a more sensible way for me to define (or get rid of) PlaceRefs in Django, please feel free to suggest alternatives.
Thanks for helping out a beginner!
First, I'd suggest rewriting the models to:
class Place(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
class Entry(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=10)
places = models.ManyToManyField(Place, related_name='places')
So you can query:
Entry.objects.filter(places__id=id)
In your current model:
Entry.objects.filter(placeref_set__place__id=id)
Note that the double underscore __ is used to jump from one model to the next. Also, django creates some fields on the model that help you navigate to related objects. In this example: Entry.placeref_set. You can read more about it here:
http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward