Django: how to get related foreign key set? - django

I'm working in Django 1.8. I have models like this:
class School(models.Model):
code = models.CharField(primary_key=True)
name = models.CharField(max_length=200)
class Meta:
app_label = 'frontend'
class SchoolStatusOnDate(models.Model):
school = models.ForeignKey(School)
date = models.DateField()
setting = models.IntegerField()
I want to retrieve all the statuses associated with a particular school, and I think I should be able to do it using _set as described here, but it isn't working. This is my code:
s = School.objects.filter(code='A81018')
now = datetime.datetime.now()
SchoolStatusOnDate.objects.create(school=s, date=now, setting=4)
print s.schoolStatusOnDate_set.all()
But this gives me the following error on the final line:
AttributeError: 'School' object has no attribute 'schoolStatusOnDate_set'
What am I doing wrong?

schoolStatusOnDate_set should be lowercase.
From Django documentation: Following relationships “backward”:
If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased.
(emphasis mine)

Related

m2m for existing table (through/unique_together)

I have found in internet different examples on how to handle m2m relations with existing DB models, such as ex1 or here ex2, however I'm still not able to solve the error I get.
My models are depicted below. Basically, all the tables where created manually.
I got the following error message:
OperationalError: (1054, "Unknown column 'supervisor_project.id' in 'field list'").
I'm still a bit confused on when to use unique_together with through. Do you see any errors in the model below? The table supervisor_project has no id field and its PK is composed actually of two FK's, i.e. surrogate PK.
class Supervisor(models.Model):
name = models.CharField(max_length=45, blank=True, null=True, help_text="Name, e.g. John Smith")
class Meta:
managed = False
db_table = 'supervisor'
def __unicode__(self):
return self.name
class Project(models.Model):
title = models.CharField(max_length=45, blank=True, null=True)
supervisors = models.ManyToManyField(Supervisor, through='SupervisorProject', through_fields=('project', 'supervisor'))
class SupervisorProject(models.Model):
supervisor = models.ForeignKey('Supervisor', on_delete=models.CASCADE)
project = models.ForeignKey('Project', on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'supervisor_project'
unique_together = (('supervisor', 'project'),)
Django requires each model to have exactly one primary key field. It doesn't support multiple-column primary keys yet.
Since you haven't explicitly defined a primary key on the SupervisorProject model, Django assumes that there is an automatic primary key field id. When it includes the id field in a query, you get the error because it doesn't exist.
If possible, I would add an auto-incrementing id column to each intermediate table. There isn't a way to get Django to add the column to the tables automatically. You have set managed=False, so Django expects you to manage the database table.

How to access Foreign key models with custom primary key in django

These are my two models:
In models.py
class Person(models.Model):
person_no = models.IntegerField(max_length=10, primary_key='True')
phone = models.IntegerField(max_length=20)
class Meta:
db_table = 'person'
class person_ext(models.Model):
person_no = models.ForeignKey(Person)
key = models.CharField(max_length=64)
value = models.TextField()
class Meta:
db_table = 'personExt'
I went to manage.py shell to test my model and I tried to access the cell_phone of a person given the person's id this way:
p = Person.objects.get(pk=1)
cell_phone = Person_ext.objects.get(person_no=p).filter(key='cell').value
However, I'm getting the following error:
DatabaseError: (1054, "Unknown column 'personExt.person_no_id' in 'field list'")
My database column is just "person_id" but django is looking for "person_no_id". What do I have to do to access the personExt data using a person_no from person.
person_no_id is what I would expect for Django to look at. It appears that your database is actually out of sync with what your models expect. I would consider comparing the output of (sql)
SHOW CREATE TABLE `personExt `;
and
python manage.py sql APPNAME
for the table in question. You can fix this problem by using migration tools like south, recreating the database, or manually editing the database to fix the field. Alternatively you can change the model if you're importing:
person_no = models.ForeignKey(Person, db_column="person_id")
Edit: primary_key should be True, not the string "True," Indentation looks wrong for the Meta class and you should consider naming person_ext as PersonExt instead.

django: how do I query based on GenericForeignKey's fields?

I'm new in using GenericForeignKey, and I couldn't make it to work in a query statement. The tables are roughly like the following:
class Ticket(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
class Issue(models.Model):
scan = models.ForeignKey(Scan)
A scan creates one issue, an issue generates some tickets, and I made Issue as a foreign key to Ticket table. Now I have a Scan object, and I want to query for all the tickets that related to this scan. I tried this first:
tickets = Tickets.objects.filter(issue__scan=scan_obj)
which doesn't work. Then I tried this:
issue = Issue.objects.get(scan=scan_obj)
content_type = ContentType.objects.get_for_model(Issue)
tickets = Tickets.objects.filter(content_type=content_type, issue=issue)
Still doesn't work. I need to know how to do these kind of queries in django? Thanks.
The Ticket.issue field you've defined will help you go from a Ticket instance to the Issue it's attached to, but it won't let you go backwards. You're close with your second example, but you need to use the issue_id field - you can't query on the GenericForeignKey (it just helps you retrieve the object when you have a Ticket instance). Try this:
from django.contrib.contenttypes.models import ContentType
issue = Issue.objects.get(scan=scan_obj)
tickets = Ticket.objects.filter(
issue_id=issue.id,
issue_ct=ContentType.objects.get_for_model(issue).id
)
Filtering across a GenericForeignKey can by creating a second model that shares the db_table with Ticket. First split up Ticket into an abstract model and concrete model.
class TicketBase(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
class Meta:
abstract = True
class Ticket(TicketBase):
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
Then create a model that also subclasses TicketBase. This subclass will have all the same fields except issue which is instead defined as a ForeignKey. Adding a custom Manager allows it to be filtered to just a single ContentType.
Since this subclass does not need to be synced or migrated it can be created dynamically using type().
def subclass_for_content_type(content_type):
class Meta:
db_table = Ticket._meta.db_table
class Manager(models.Manager):
""" constrain queries to a single content type """
def get_query_set(self):
return super(Manager, self).get_query_set().filter(issue_ct=content_type)
attrs = {
'related_to': models.ForeignKey(content_type.model_class()),
'__module__': 'myapp.models',
'Meta': Meta,
'objects': Manager()
}
return type("Ticket_%s" % content_type.name, (TicketBase,), attrs)

django admin gives warning "Field 'X' doesn't have a default value"

I have created two models out of an existing legacy DB , one for articles and one for tags that one can associate with articles:
class Article(models.Model):
article_id = models.AutoField(primary_key=True)
text = models.CharField(max_length=400)
class Meta:
db_table = u'articles'
class Tag(models.Model):
tag_id = models.AutoField(primary_key=True)
tag = models.CharField(max_length=20)
article=models.ForeignKey(Article)
class Meta:
db_table = u'article_tags'
I want to enable adding tags for an article from the admin interface, so my admin.py file looks like this:
from models import Article,Tag
from django.contrib import admin
class TagInline(admin.StackedInline):
model = Tag
class ArticleAdmin(admin.ModelAdmin):
inlines = [TagInline]
admin.site.register(Article,ArticleAdmin)
The interface looks fine, but when I try to save, I get:
Warning at /admin/webserver/article/382/
Field 'tag_id' doesn't have a default value
This can also happen if you have a disused field in your database that doesn't allow NULL.
The problem was that in the DB, tag_id wasn't set as an autoincrement field.
What solved this issue in my case was disabling STRICT_TRANS_TABLES SQL mode which was enabled by default.

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