Changing name of Foreign Key items at admin page in Django - django

I have created two Django models, were a field from one model is a Foreign key to another (as per below).
class Units(models.Model):
name = models.CharField(max_length=10, primary_key=True)
symbol = models.CharField(max_length=5)
class Targets(models.Model):
name = models.CharField(max_length=100)
unit = models.ForeignKey(MicroNutrientUnits)
...
These models are then registered to the admin site via admin.site.register. When adding an item to table Target unit correctly reflects items from table Units, however are represented in a dropdown with the name Units objects for each entry.
How can I set the name in the admin dropdown to Units.name in the admin config page?

I had the same issue when I started playing with the admin screens. I don't know if there is a better way to do this but what I did was modify the models.py file to tell my classes what to return as a default string. In your case what I would do is add the following to your Units class definition.
class Units(models.Model):
name = models.CharField(max_length=10, primary_key=True)
symbol = models.CharField(max_length=5)
def __str__(self):
return self.name
This way, when you use the foreign key link to the table, django will display the name of each unit in the dropdown list instead of just the word 'Units' over and over.

Related

Bypassing the unique constraint when defining a foreign key to just one field in Django

I've a model as shown below:
class Instance(models.Model):
data_version = models.IntegerField(default=1, unique=True)
name = models.CharField(max_length=200)
The data_version field has to be related to all other models in the application:
class Source(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
version = models.ForeignKey(Instance, on_delete=models.CASCADE, to_field='data_version', null=True)
The problem here is that Django requires the field data_version to be a unique field for me to be able to define such a relationship but that simply doesn't fit into my use case. I need to have multiple Instance objects in the app, each with version numbers starting from 1.
What I'd like is to have a unique constraint on the combination of name and data_version but then Django doesn't allow defining Foreign key relationships as shown above. Is there a way I can bypass this restriction?

Django admin Add form - Limit number of displayed Model by foreign key when date is within range

Consider I have the below simple model:
class Dimdate(models.Model):
id = models.AutoField(db_column='Id', primary_key=True) # Field name made lowercase.
date = models.DateField(db_column='date') # Field name made lowercase.
This table is used by many others models (so Dimdate.id is the FK) as below:
class MyModel(models.Model):
id = models.AutoField(db_column='Id', primary_key=True) # Field name made lowercase.
dateid = models.ForeignKey(Dimdate, models.DO_NOTHING, db_column='DateId', blank=True, null=True) # Field name made lowercase.
# ...
My problem is that DimDate table contains too many records. When using Django admin UI to add a new MyModel instance, the dropdown menu is showing all of my DimDate which makes it not user friendly.
I did a quick google search but found nothing to restrict the number of DimDate elements retrieved and displayed in the dropdown menu (when adding a MyModel instance).
Can I filter my dimdate to include only the dates from 1 month in the past to 1 month in the future?
Eg: If we are the 27th of Jan 2020. Dates range is: [27/12/2019, 27/02/2020]
I am currently using the admin "classic" approach of django (no custom form):
#admin.register(models.MyModel)
class MyModelAdmin(admin.ModelAdmin):
I suspect I will need to override the MyModel form. But even by doing it. How can I limit the number of retrieved DimDate inside my form?
Is there an easier way of doing (as I am new with Django...)?
In case it is needed, I am using Django 2.2.6
use raw_id_fields in your admin config to prevent loading all objects
#admin.register(models.MyModel)
class MyModelAdmin(admin.ModelAdmin):
raw_id_fields = ('dateid',)`
it shows up like bellow and you can select object when clicking on it on new window
and if you want just filter dropdown items you can add limit_choices_to to you foreignkey field like bellow:
def limit_dim_date_choices():
return {'date__range': (date(2019,12,27), date(2020,2,27))}
class MyModel(models.Model):
id = models.AutoField(db_column='Id', primary_key=True) # Field name made lowercase.
dateid = models.ForeignKey(Dimdate, limit_choices_to=limit_dim_date_choices, models.DO_NOTHING, db_column='DateId', blank=True, null=True) # Field name made lowercase.
# ...

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.

Django Model Inheritance -- prevent subclass instances from appearing in superclass admin

I have two classes:
class Article(ContentAsset):
title = models.CharField(max_length=2000)
author = models.CharField(max_length=2000, blank=True)
source = models.CharField(max_length=2000, default="")
datePublished = models.DateField(default=datetime.now)
def __unicode__(self):
return self.title
and
class PubMedArticle(Article):
pubMedID = models.CharField(max_length=100)
abstract = models.TextField(max_length=20000)
All of the PubMedArticle instances show up in the admin interface twice -- under the list of all PubMedArticle objects , and list of all Article objects. Is this normal behavior? I'd think that a subclass wouldn't normally show up in the admin list of its superclass. What's the best way to ensure that these PubMedArticle objects show up only under the PubMedArticle admin list?
This is normal behavior. From database point of view table primary key of PubMedArticle just refers to Article table. So for each record in PubMedArticle table must be a record in Article table.
Now to the admin. The are two ways:
1) Make Article model abstarct - a good idea if you dont need unique primary keys to all of your articles.
2) Customize django admin list query.

How can i filter a ManyToManyField on the basis of ForeignKey in django? (Something like Django Smart Select do)

I have four models in my models.py which are:
models.py
class Course(models.Model):
course_code = models.CharField(max_length=100,unique=True)
title = models.CharField(max_length=200)
short = models.CharField(max_length=50)
elective_group = models.CharField(max_length=100)
class Unit(models.Model):
title = models.CharField(max_length=100)
short = models.CharField(max_length=50)
course = models.ForeignKey(Course)
class Pattern(models.Model):
pattern_name = models.CharField(max_length=200)
class ExamSchedule(models.Model):
exam_date = models.DateTimeField()
course = models.ForeignKey(Course)
pattern = models.ForeignKey(Pattern)
units = models.ManyToManyField(Units)
I have all these models register with admin site, so that i can use admin functionality for these models.
My problem is when a user creates or edits a ExamSchedule object , i want the units(field) multivalue widget should contains only those values that are associated with a course as every course can have multiple units. So if user creates an Examschedule object and after selecting a course from dropdown the unit widget should only contains those units that related to the course selected.
Django-Smart-Select could have been useful but it only supports foreign key chained and grouped selects nor ManyToManyField chained select.
Thanks
You can send the selected course with a Ajax request and do this to get the related units.
Lets say you select communication networks (cn) as the course you can get the related units like so:
cn_units = Unit.object.filter(course = 'cn').values_list('id',flat=True)
This will return a single list of all the related units to that course.
You can send this list as a response to your ajax request, iterate over this list and populate the select box for unit in ExamSchedule form. I consider plain ajax because its very flexible.