Django - Get name of model object by iterating through class - python

I'm new to Python (and pretty inexperienced at programming in general), but I have an issue I can't for the life of me figure out.
I'm trying to pre-populate a field in my database with the name of an instance from another model/class in my database. The model with the field I want to pre-populate is an "instance" of the model instance from which I'm trying to grab the name, and has a foreign key to that instance.
Goal: 1) User selects the parent of the object by assigning the foreign key to the parent 2) A function grabs the name of the parent instance matching the foreign key the user selected. 3) the result from that function is used as the default value for the field.
Here's the code:
class Injury(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular injury')
name = models.CharField(max_length=200, help_text='Enter an injury or complication (e.g. respiratory failure)')
description = models.TextField(max_length=1000, blank=True, help_text='Describe the injury')
time_to_onset = models.PositiveIntegerField(blank=True, validators=[MaxValueValidator(10000)], help_text='Enter expected time from trigger until injury/complication onset')
findings = models.TextField(max_length=1000, blank=True, help_text='Enter the signs and symptoms of the injury or complication')
vitals_trends = models.TextField(max_length=1000, blank=True, help_text='Enter the vitals changes due to the injury')
class Meta:
ordering = ['name']
def __str__ (self):
return self.name
def get_absolute_url(self):
return reverse('Injury-detail', args=[str(self.id)])
class Injury_Instance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular injury')
parent_case = models.ForeignKey(PFC_Case, on_delete=models.SET_NULL,null=True)
injury_model = models.ForeignKey(Injury, on_delete=models.SET_NULL, null=True)
def set_injury_name(self):
for injuries in Injury.all()
if injury_model == injuries
break
return Injury.name
name = dislay_models.CharField(default=set_injury_name(self,Injury,injury_model), max_length=100)
triggered_by = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)
def __str__ (self):
return self.name
def get_absolute_url(self):
return f'{self.id} ({self.Injury.name})'
The problem area is def set_injury_name and Injury_Instance.name
Thanks!!!
Edit:
I tried the following code, but I'm getting the error 'NameError: name 'self' is not defined'
class Injury_Instance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular injury')
parent_case = models.ForeignKey(PFC_Case, on_delete=models.SET_NULL,null=True)
injury_model = models.ForeignKey(Injury, on_delete=models.SET_NULL, null=True)
def get_injury_name(self):
return self.name
injury_name=get_injury_name(self)
name = models.CharField(default=injury_name, max_length=100)
triggered_by = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)
def __str__ (self):
return self.name
def get_absolute_url(self):
return f'{self.id} ({self.Injury.name})'

You don't need to store the name of your foreign key field as you always can access it with:
self.injury_model.name
If you need to get access it just by name you can write a property in Injury_Instance model.
#property
def name(self):
return self.injury_model.name

Related

How to write __str__ func in this case?

I have a 'user' model that have a OneToOneField to User Model and another model named 'user_agent' that have a foreign key to 'user' model. How can I use 'first_name' and 'last_name' in the __str__ func?!
class users(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, default='')
user_type = models.ForeignKey(types, on_delete=models.SET_NULL, blank=True, null=True)
mobile = models.CharField(max_length=20)
active_code = models.CharField(max_length=50, blank=True)
date_send_active_code = models.DateField(default=now, blank=True)
count_send_active_code = models.IntegerField(default=0)
token = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class user_agent(models.Model):
user = models.ForeignKey(user_models.users, on_delete=models.CASCADE)
agent = models.ForeignKey(agents, on_delete=models.CASCADE)
parent = models.ForeignKey("self", on_delete=models.CASCADE, default='1')
def __str__(self):
return "(" + self.user.first_name + " " + self.user.last_name + ")"
You want self.user.user.first_name - but I kindly suggest you change your user model name to something like Profile to avoid confusion (and use CamelCase for your models names in general).
def __str__(self):
return "({} {})".format(self.user.first_name, self.user.last_name)
or if you're using python 3, use f strings:
def __str__(self):
return f"({self.user.first_name} {self.user.last_name})"
EDIT: not sure if you're asking about the user or user_agent model, if it's the user model, then just use the code above but with self.first_name and self.last_name instead.
Also, typically python classes are upper case without underscores:
class User(models.Model) and class UserAgent(models.Model)

Django AttributeError: 'ForwardManyToOneDescriptor' object has no attribute <field>

I've got 4 related models in one app:
class AssetType(models.Model):
id = models.AutoField(primary_key=True)
type_name = CaseInsUniqueCharField(name='Type Name')
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, verbose_name='parent')
type_field = models.ManyToManyField('AssetField', blank=True)
history = HistoricalRecords()
# Return Asset Name for Queries
def __str__(self):
return self.type_name
class AssetField(models.Model):
id = models.AutoField(primary_key=True)
field_name = CaseInsUniqueCharField(name='Field Name')
history = HistoricalRecords()
# Return Field Name for Queries
def __str__(self):
return self.field_name
class AssetFieldValue(models.Model):
id = models.AutoField(primary_key=True)
value = models.CharField('value', blank=True, max_length=100)
field = models.ForeignKey('AssetField', on_delete=models.CASCADE, blank=False)
asset = models.ForeignKey('Asset', on_delete=models.CASCADE, blank=False)
history = HistoricalRecords()
# Return '<Asset> - <Value>' for Queries
def __str__(self):
return str(self.asset) + "-" + str(self.field)
class Asset(models.Model):
id = models.AutoField(primary_key=True)
asset_type = models.ForeignKey('AssetType', on_delete=models.CASCADE, verbose_name='Type')
asset_name = models.CharField('Name', max_length=100)
asset_tag_no = models.CharField('Tag Number', max_length=20, blank=True, null=True)
asset_manufacturer = models.ForeignKey('AssetManufacturer', on_delete=models.SET_NULL, null=True, blank=True)
asset_storage_location = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)
asset_list_price = models.PositiveSmallIntegerField('List Price', blank=True, null=True)
asset_needs_pat = models.BooleanField('Needs Electrical Test', null=True)
asset_fields = models.ManyToManyField('AssetField', blank=True, editable=False)
history = HistoricalRecords()
# Return Asset name for queries
def __str__(self):
return self.asset_name
And I have added in a post-save handler just under the Asset Class
#receiver(post_save, sender=Asset)
def my_handler(sender, **kwargs):
t = Asset.asset_type
f = t.type_field.all()
for i in range(1,f.count()+1):
Asset.asset_fields.add(f[i-1:i])
That is supposed to add the AssetFields records that are related to the Asset's AssetType. When I run the following in the django shell I am able to successfully add the relationships to the Asset ManyToMany field asset_fields
>>> a = Asset.objects.first()
>>> t = a.asset_type
>>> f = t.type_field.all()
>>> for i in range(1, f.count()+1):
... a.asset_fields.add(f[i-1:i][0])
However when I save an asset, with the same type t as used in the shell, through the admin page I get the error:
AttributeError at /admin/assets/asset/add/
'ForwardManyToOneDescriptor' object has no attribute 'type_field'
I'm not sure where this error is coming from as the same functions ran in the shell without any issues, unless potentially I'm dealing with the #reciever wrong? Any ideas?
But you don't do the same thing in the view as you do in the shell. In the shell, you access asset_type on a specific instance of Asset. In the view, you call it on the class itself. That doesn't make sense; as with the shell version, you need to query or create an instance, then you can access its asset_type - and call asset_fields.add().
I suspect, since this is a signal handler on Asset, you actually wanted to use the instance that is being saved. In which case:
def my_handler(sender, instance, **kwargs):
t = instance.asset_type
f = t.type_field.all()
I also can't understand what your loop is doing there. I suspect you mean:
for type in t.type_field.all()
instance.asset_fields.add(t)

Django- limit_choices_to using 2 different tables

I fear that what I am trying to do might be impossible but here we go:
Among my models, I have the following
Class ParentCategory(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
Class Category(models.Model):
parentCategory = models.ForeignKey(ParentCategory, on_delete=models.CASCADE, )
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
Class Achievement(models.Model):
milestone = models.ForeignKey(Milestone, on_delete=models.CASCADE)
description = models.TextField( )
level_number = models.IntegerField()
completeion_method = models.ForeignKey(Category, on_delete = models.CASCADE, limit_choices_to={'parentCategory.name':'comp method'})
def __unicode__(self): # TODO:
return description[0,75] + '...'
I know the completion method field throws an error because it is not correct syntax. But is there a way to achieve the wanted result using a similar method?
Maybe this will work:
limit_choices_to={'parentCategory__name': 'comp method'}

Django Queryset foreign keys

I am trying to get a queryset but it is not displaying anything. Basically, I want to get the Asset objects that are assigned via foreign key to an employee, which is a foreign key of the signed in user.
views.py
def get_queryset(self):
assetlist = Asset.objects.filter(organisation__employee__user=self.request.user)
print(assetlist)
return assetlist
models.py
class Employee(models.Model):
name = models.CharField("Employee Name", max_length=50, blank=False)
email = models.CharField("Employee Email", max_length=50, blank=True)
user = models.ForeignKey(User)
clientID = models.ForeignKey(Organisation)
def save(self):
self.name = self.user.get_full_name()
self.email = self.user.email
super(Employee, self).save()
def __str__(self):
return self.name
class Asset(models.Model):
name = models.CharField("Asset Name", max_length=30, primary_key=True)
organisation = models.ForeignKey(Organisation)
def __str__(self):
return self.name
class Organisation(models.Model):
name = models.CharField("Organisation Name", max_length=50, blank=False)
location = models.TextField("Organisation Address", max_length=200, blank=True)
tel = models.CharField("Telephone Number", max_length=20)
def __str__(self):
return self.name
There is no employee field inside organisation. It's an reversed relation, there are many employees attached so you can't query it like that.
But there is something called related_name in django foreign keys, with use of that, your query should look like that:
assetlist = Asset.objects.filter(organisation__employee_set__user=self.request.user)
or if you specify your own related_name into employee -> organisation relation:
clientID = models.ForeignKey(Organisation, related_name="employees")
it will look like this:
assetlist = Asset.objects.filter(organisation__employees__user=self.request.user)
The answer was to approach from another model, as seen below:
assetlist = Sensor.objects.filter(asset__organisation__employee__user=self.request.user)
You have written wrong code. You want an Asset object by using:
assetlist = Asset.objects.filter(organisation__employee__user=self.request.user)
But you clearly can see in your models.py that there is no relationship between Organisation and Employee, then how can you get a result using organisation__employee...?
You should first create a ForeignKey field to relate with Employee model then your code will work fine.

NameError: name 'ManyToManyField' is not defined

I'm trying to use a ManyToMany relationship and it is giving me the following error:
NameError: name 'ManyToManyField' is not defined
Background: Building a to do app where users have (many) projects, projects have (many) lists of tasks and projects have (many) tags that characterise them.
Here is my models.py, any help catching the error would be greatly appreciated.
from django.db import models
from django.contrib.auth.models import User
#Not sure if I need the ID's. They may be superfluous. Ask in the lab today.
#Used to list collaborators on projects and track friends lists
#Borrowed from http://stackoverflow.com/a/1113039/1254402
class SeparatedValuesField(models.TextField):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
self.token = kwargs.pop('token', ',')
super(SeparatedValuesField, self).__init__(*args, **kwargs)
def to_python(self, value):
if not value: return
if isinstance(value, list):
return value
return value.split(self.token)
def get_db_prep_value(self, value):
if not value: return
assert (isinstance(value, list) or isinstance(value, tuple))
return self.token.join([unicode(s) for s in value])
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
class UserProfile(models.Model):
user_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
user = models.OneToOneField(User)
# The additional attributes we wish to include.
first_name = models.CharField(max_length=64)
surname = models.CharField(max_length=64)
friends = SeparatedValuesField()
picture = models.ImageField(upload_to='profile_images', blank=True)
projects = models.ManyToManyField('Project')
# This line is required. Links UserProfile to a User model instance.
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
#Project model.
#Attributes = name, website, team members
#Many users can have many projects
class Project(models.Model):
project_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
name = models.CharField(max_length=128)
description = models.CharField(max_length=300)
website = models.URLField(blank=True)
team_members = SeparatedValuesField()
class List(models.Model):
#Many lists belong to one project
project = models.ForeignKey(Project)
tasks = ManyToManyField('Task')
name = models.CharField(max_length=128)
colour = models.CharField(max_length=10)
#NOTE! - Abstracting the tags (category, progress and priority) to project level.
class Task(models.Model):
#Many tasks belong to one list
belong_to_list = models.ForeignKey(List)
#Unique id for task
task_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
#Standard title & description
title = models.CharField(max_length=100)
description = models.CharField(max_length=300)
#NOTE! - Abstracting the tags (category, progress and priority) to project level.
class Tag(models.Model):
project = models.ForeignKey(Project)
#UUID
task_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
#User assigns each tag a colour. hex code.
colour = models.CharField(max_length=10)
In List, you are referring to ManyToManyField without referencing it via models as you do with all the other fields.
Note that the error message would have told you exactly where the problem was, so that you wouldn't have needed to post all the other irrelevant code.

Categories