Set admin date_hierarchy to a ForeignKey date field - django

When I try to set
date_hierarchy = "schedule__date"
Where schedule is a foreign key.
I get the following error.
'TestAdmin.date_hierarchy' refers to field 'schedule__date' that is missing from model 'testing.Test'.
I understand the error. What I'm hoping for is that there is some sort of workaround here to allow me to have date_hierarchy from a foreign key date field. I have tried setting a method and propery within the Test model that returns the date and setting that method/property as the date_hierarchy, but no luck.
It seems foolish to have to add another column to my table for the schedule__date when I already have it stored in another table from the foreign key.

The ability to reference fields on related models was added in Django 1.11:
Minor features
django.contrib.admin
ModelAdmin.date_hierarchy can now reference fields across relations.
https://docs.djangoproject.com/en/1.11/releases/1.11/

Unforturnately, this isn't possible with the current django. The date_hierarchy option is explicitly required to be a DateTimeField or DateField:
https://github.com/django/django/blob/stable/1.10.x/django/contrib/admin/checks.py#L837

Related

How to get all id from model in django [duplicate]

I have a table called user_info. I want to get names of all the users. So the table has a field called name. So in sql I do something like
SELECT distinct(name) from user_info
But I am not able to figure out how to do the same in django. Usually if I already have certain value known, then I can do something like below.
user_info.objects.filter(name='Alex')
And then get the information for that particular user.
But in this case for the given table, I want to get all the name values using django ORM just like I do in sql.
Here is my django model
class user_info(models.Model):
name = models.CharField(max_length=255)
priority = models.CharField(max_length=1)
org = models.CharField(max_length=20)
How can I do this in django?
You can use values_list.
user_info.objects.values_list('name', flat=True).distinct()
Note, in Python classes are usually defined in InitialCaps: your model should be UserInfo.
You can use values_list() as given in Daniel's answer, which will provide you your data in a list containing the values in the field. Or you can also use, values() like this:
user_info.object.values('name')
which will return you a queryset containing a dictionary. values_list() and values() are used to select the columns in a table.
Adding on to the accepted answer, if the field is a foreign key the id values(numerical) are returned in the queryset. Hence if you are expecting other kinds of values defined in the model of which the foreign key is part then you have to modify the query like this:
`Post.objects.values_list('author__username')`
Post is a model class having author as a foreign key field which in turn has its username field:
Here, "author" field was appended with double undersocre followed by the field "name", otherwise primary key of the model will be returned in queryset. I assume this was #Carlo's doubt in accepted answer.

Django m2m field. Through model with multiple foreign keys (fk) to same model type

I wanted all instances in all tables to have an object instance. A one to one primary key field looked like a good way to do this. Like a small example below.
from util.fields import BigAutoField,BigForeignKey
from django.db import models
class Common_document(models.Model):
pk = models.OneToOneField("Type_object", primary_key=True, related_name="common_document_content_pk")
author = models.ManyToManyField("Type_object", related_name = 'common_document_author',
limit_choices_to = {"Common_document_author_author":"Type_object"} ,null = True,
through = 'Common_document_author', blank = True)
#....
class Common_document_author(models.Model):
pk = models.OneToOneField("Type_object", primary_key=True, related_name="common_document_author_pk")
document = BigForeignKey("Common_document", related_name='Common_document_author_document')
author = BigForeignKey("Type_object", related_name='Common_document_author_author')
class Type_object(models.Model):
id = BigAutoField(primary_key=True)
#....
# Some of the fields are m2m
However this gave the following error:
django.core.management.base.CommandError: One or more models did not validate:
schema.common_document: Intermediary model Common_document_author has more than
one foreign key to Type_object, which is ambiguous and is not permitted.
This error is removed if I comment out the pk field in the document_author table. I guess the error comes because django is not sure witch object FK to use. How do i fix this? Is there a way to tell django which field in the m2m table to be used in the m2m field?
I am probably not going to do it like this. m2m tables are probably not going to need to have an object instance, but I would still like to know how to do this.
I guess I don't understand you motivation. Why do you want to use a foreign key as your primary index? Sure, index it, but primary?. You might also try changing its name from 'pk', I am sure Django makes assumptions about the field called 'pk'.

How should a many-to-many table be defined

I'm having some trouble understanding many-to-many fields in Django.
When I create a many-to-many field, ex:
class GlobalPart (Models.model):
...
category_id=models.ManyToManyField(Category, related_name = 'globalpart')
...
and
class Category (Model.model):
...
category = models.CharField(max_length=250)
...
I notice that it created a new table called appname_globalpart_category_id in addition to the appname_globalpart table for the GlobalPart model.
What I'm wondering is, how should the field types in that table be defined. I would think that
there should be at least one foreign key there to relate the fields. But instead there is the primary key for the table, and the other fields are integers (globalpart_id and category_id).
So my question is -- is that normal? Or did I somehow define the many-to-many field incorrectly? And my next question is how would I get all the category_ids associated to a particular GlobalPart?
(1) short answer: Yes this is normal.
Long answer: ManyToMany table will need a foreign key to both Category and GlobalPart tables. Strictly speaking those two foreign keys should be sufficient. The extra pk that you see in there is just for django magic. You can really get away with only those two foreign keys in that table if you manually define the many-to-many table yourself. However if you let django do it for you (by using ManyToManyField) you get this extra pk
(2) I suggest changing your model fields category_id to categories:
class GlobalPart (Models.model):
categories=models.ManyToManyField(Category, related_name = 'globalpart')
This is because, ManyToManyFields refers well to "many" items. This field does not refer to "one" category_id, it refers to all related categories. So when naming it would be natural to name it accordingly.
As for accessing all categories you can do it by accessing the "categories" property. Say if your object instance named global_part, you can access categories like this:
categories = global_part.categories.all()
Instead of all(), you can use filter() or exclude() the same way you use it when querying models.
Here is a link to related django docs
What do you think a foreign key is? It's a field containing values that equate to IDs - usually primary keys - in the "foreign" table. If the other table has integer keys, as most Django tables do, then the foreign key field will be of type integer as well.
Additionally, Django creates constraints so that the database will enforce that the IDs do actually reference valid values in the foreign table. Depending on your database, these might or might not be displayed as part of the field definition.

Edit/show Primary Key in Django Admin

It appears Django hides fields that are flagged Primary Key from being displayed/edited in the Django admin interface.
Let's say I'd like to input data in which I may or may not want to specify a primary key. How would I go about displaying primary keys in the admin interface, and how could I make specifying it optional?
I also wanted to simply show the 'id' (primary key) within the Django admin, but not necessarily edit it. I just added it to the readonly_fields list, and it showed up fine. IE:
class StudentEnrollmentInline(admin.TabularInline):
model = Enrollment
readonly_fields=('id',)
whereas if I tried to add it to the 'fields' list, Django got upset with me, saying that field didn't exist...
If you explicitly specify the primary key field in your models (with primary_key=True), you should be able to edit it in the admin.
For Django models created via ./manage.py syncdb the following primary key field is added automatically:
id = models.AutoField(primary_key=True)
if you change (or add) that to your model explicitly as an IntegerField primary key, you'll be able to edit it directly using the admin:
id = models.IntegerField(primary_key=True)
But as others pointed out, this is a potential minefield...
To show the primary key, which by default will have a column name of "id" in the database - use "pk"
def __str__(self):
return '{} - {} ({})'.format(self.pk, self.name, self.pcode)
It doesn't make sense to have an optional primary key. Either the PK is an autoincrement, in which case there's no need to edit it, or it's manually specified, in which case it is always required.
Why do you need this?
In django documentation, there is a short sentence about that, which is not clear:
If neither fields nor fieldsets options are present, Django will default to displaying each field that isn't an AutoField and has editable=True, in a single fieldset, in the same order as the fields are defined in the model.
Reason is, django do not allow you to edit an AutoField by any means (and that is the right thing since it is an auto increment value and should not be edited). #mnelson4's answer is a good approach to display it.
The answer with the highest votes didn't work for me. I needed a getter.
class StudentEnrollmentInline(admin.TabularInline):
model = Enrollment
readonly_fields=('student_enrollment_id',)
def student_enrollment_id(self, obj):
return obj.id
Using django 1.11

Django model with 2 foreign keys from the same table

I wanted a Django model with 2 foreign keys from the same table. It's an event table which has 2 columns for employees: the 'actor' and the 'receiver'. But I get this error:
Error: One or more models did not validate: tasks.task: Intermediary
model TaskEvent has more than one foreign key to Employee, which is
ambiguous and is not permitted.
Is there a better way to model this?
I think I'm going to add a TaskEvent_to_Employee table. There will be two records in it, one for each of the two employees related to each TaskEvent. Does anyone know an easier workaround?
I haven't done this yet, but I used inspectdb to generate the models.py file from an existing DB that does exactly that - this is what inspectdb threw back, so it should work:
creator = models.ForeignKey(Users, null=True, related_name='creator')
assignee = models.ForeignKey(Users, null=True, related_name='assignee')
Hope that works for you - if it doesn't I am going to have a problem too.
I think what you're looking for is the related_name property on ForeignKeyFields. This will allow you to reference the same table, but give django special names for the relationship.
More Info:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
https://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/
From the error message, it sounds like you're trying to put two foreign keys to the same object on an intermediary table used via the through argument to ManyToManyField, the documentation for which states:
When you set up the intermediary
model, you explicitly specify foreign
keys to the models that are involved
in the ManyToMany relation. This
explicit declaration defines how the
two models are related.
There are a few restrictions on the
intermediate model:
Your intermediate model must contain one - and only one - foreign key to
the target model (this would be Person
in our example). If you have more than
one foreign key, a validation error
will be raised.
Your intermediate model must contain one - and only one - foreign key to
the source model (this would be Group
in our example). If you have more than
one foreign key, a validation error
will be raised.
Using related_name was my solution:
class Sample(models.model):
...
class Mymodel(models.model):
example1 = models.ForeignKey(Sample, related_name='sample1')
example2 = models.ForeignKey(Sample, related_name='sample2')
The fact that two columns are part of one table implies that the two fields are related, therefor to reference them individually is not ideal. The ForeignKey of your model should be the primary key of the table you are referencing:
event = models.ForeignKey('event')
You would then reference the columns as such:
foo.event.actor
foo.event.receiver
If you wish you could also change the way your class/model references the foreign attributes with properties. In your class you would do the following:
#property
def actor(self):
return self.event.actor
#property
def receiver(self):
return self.event.receiver
This would allow you to then call foo.actor and foo.receiver but I believe the longer, foo.event.actor would be more pythonic