I have the following models:
class Name(models.Model):
device_type = models.CharField('Device Type', max_length=30, blank=True, null=True)
class Device(models.Model):
DEVICE_TYPE_CHOICES = (
('Router', 'Router'),
('Switch', 'Switch'),
('Firewall', 'Firewall'),
('Load Balancer', 'Load Balancer'),
)
device_name = models.CharField('Device Name', max_length=100)
device_type = models.CharField('Device Type', max_length=20, blank=True, null=True, choices=DEVICE_TYPE_CHOICES)
Given the above, right now when I create a new object using my Device model, choices for device_type are defined statically using the Field.choices method and this shows up in Django Admin as a drop down list with the four choices shown.
What I really want is to have that list of choices defined dynamically based on the following concept which basically says "from the Name model/table return a list of all values found in the 'device_type' column":
Name.objects.all().values_list('device_type')
I'm just not sure how to put this into practice. I'm not sure how to take the list which I already know how to get from my database and incorporate it into the Field.objects method so that those items show up as choices in my drop down menu.
Can anyone point me in the right direction? Thanks in advance for any assistance.
UPDATE AFTER FOREIGN KEY FIX:
Now my models look like this:
class Name(models.Model): # device type naming standards
device_type = models.CharField('Device Type', max_length=30, blank=True, null=True)
device_alias = models.CharField('Device Alias', max_length=30, blank=True, null=True)
def __unicode__(self):
return self.device_type
class Device(models.Model):
location_name = models.ForeignKey('Location')
device_name = models.CharField('Device Name', max_length=100)
device_type = models.ForeignKey('Name')
#device_type = models.CharField('Device Type', max_length=20, blank=True, null=True, choices=DEVICE_TYPE_CHOICES)
Now you'll see in my Device model I have two ForeignKeys. I need Location to be a ForeignKey because I want to put Devices categorically under a specific Location. I need the device type ForeignKey per my previous question. When I have two ForeignKeys like this, when I go to my Device table in Django Admin, I see no devices (even though they were in the table before I created the device_type ForeignKey. If I comment out the device_type ForeignKey and uncomment out the last line to go back to what I had before (after updating the schema with 'makemigrations' and 'migrate', now the devices show up again. Obviously I need the devices to show up in my device table. Am I allowed to have multiple ForeignKeys? I'm sure I'm not understanding something critical here.
If you will use ForeignKey, you'll get the list of name devices
device_type = models.ForeignKey('Name')
def __unicode__(self):
return self.device_type
Hope it help you.
Related
I'll shorten the code as simple as possible. Supposedly, we do have two models.
models.py > Products table
CATEGORY = (
('Hard Disk Drive', 'Hard Disk Drive'),
('Solid State Drive', 'Solid State Drive'),
('Graphics Card', 'Graphics Card'),
('Laptop', 'Laptop'),
('RAM', 'RAM'),
('Charger', 'Charger'),
('UPS', 'UPS'),
('Mouse', 'Mouse'),
('Keyboard', 'Keyboard'),
('Motherboard', 'Motherboard'),
('Monitor', 'Monitor'),
('Power Supply', 'Power Supply'),
('Router', 'Router'),
('AVR', 'AVR'),
('Tablet', 'Tablet'),
('System Unit', 'System Unit'),
('Audio Devices', 'Audio Devices'),
('CPU', 'CPU'),
('Others', 'Others'),
)
class Product(models.Model):
model_name = models.CharField(max_length=100, null=True, blank=True)
asset_type = models.CharField(max_length=20, choices=CATEGORY, blank=True)
date = models.DateField(null=True, blank=True)
And the other table > Order table
class Order(models.Model):
product_order = models.ForeignKey(Product, on_delete=models.CASCADE, null=False)
employee = models.ForeignKey(User, models.CASCADE, null=False)
date = models.DateTimeField(auto_now_add=True)
remarks = models.TextField()
And we all know that adding this code will limit the foreignkey choices under the Order form.
limit_choices_to={"asset_type": "Hard Disk Drive"}
limit_choices_to={"asset_type": "Solid State Drive"}
My goal here is to show items from Products table whose asset_type is either "Hard Disk Drive" OR "Solid State Drive". I've read the documentation of Django for "limit_choices_to" and can't see any pertaining to some kind of solution in here. Thank you in advance who knows a way to make this possible.
You can work with the __in lookup [Django-doc] to specify a list of allowed values:
class Order(models.Model):
product_order = models.ForeignKey(
Product,
on_delete=models.CASCADE,
limit_choices_to=dict(asset_type__in=['Hard Disk Drive', 'Solid State Drive'])
)
# …
Note: Specifying null=False [Django-doc] is not necessary: fields are by default not NULLable.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I have what i think is a simple question but I am struggling to find out how it works. I get how related name works for foreign keys but with many to many fields it seems to break my brain.
I have two 3 models at play here. A User, TeamMember and Team Model as seen below.
User model is the built in django model.
#TeamMember Model
class TeamMember(models.Model):
member = models.ForeignKey(User, on_delete=models.SET(get_default_team_member), verbose_name='Member Name', related_name="team_members")
...
#Team Model
class Team(models.Model):
name = models.CharField(max_length=50)
manager = models.ForeignKey(TeamMember, on_delete=models.SET_NULL, related_name="managers", null=True, blank=True)
team_lead = models.ForeignKey(TeamMember, on_delete=models.SET_NULL, related_name="tls", null=True, blank=True)
tps = models.ForeignKey(TeamMember, on_delete=models.SET_NULL, related_name="tps", null=True, blank=True)
members = models.ManyToManyField(TeamMember, blank=True, related_name="members")
...
Now in a view i want to access a specific users team. I thought i could do this by doing something like this:
member = TeamMember.objects.get(pk=1)
member_team = member.members.name
However if I print member_name than it prints nothing. If I try to access any of the other fields on that model like member.members.team_lead.first_name it fails to find the team_lead field. I understand that this has a .all() attribute but i thought it was tied to the team object through the members field. So if that member matches the team it would give me the team. So I thought it might be an issue if the same member was linked to more than one team (which is possible) so i tired something like this member.members.all().first().name and i get an error that states it cannot get name from NoneType.
Is there an easy way to get the team name from a relationship like this or am i better off just doing a team query with the user?
Thanks,
jAC
First of all, I would like to point out that you are not using the related_name (and related_query_name parameters in a proper way). I think this SO post will help you to understand the concept in a better way.
So, I would change the related_name (and related_query_name) values in the Team model as below,
class Team(models.Model):
name = models.CharField(max_length=50)
manager = models.ForeignKey(
TeamMember,
on_delete=models.SET_NULL,
related_name="teams",
related_query_name="team",
null=True,
blank=True,
)
team_lead = models.ForeignKey(
TeamMember,
on_delete=models.SET_NULL,
related_name="teams",
related_query_name="team",
null=True,
blank=True,
)
tps = models.ForeignKey(
TeamMember,
on_delete=models.SET_NULL,
related_name="teams",
related_query_name="team",
null=True,
blank=True,
)
members = models.ManyToManyField(
TeamMember, blank=True, related_name="teams", related_query_name="team"
)
...
Now in a view i want to access a specific user's team.
Since the Team and TeamMember models are connected via ManyToManyField, you may have "zero or more" Teams associated with a single TeamMember
So, the following query will get you all the teams associated with a particular TeamMemeber
team_member = TeamMember.objects.get(pk=1)
all_teams = team_member.teams.all()
You can also iterate over the QuerySet as,
team_member = TeamMember.objects.get(pk=1)
for team in team_member.teams.all():
print(team.name)
For anyone wondering what I did based on JPG's advice was the for loop option
team_member = TeamMember.objects.get(pk=1)
teams = [t.name for t in team_member.members.all()]
I personally do not care which team i get as my need in this case is just to pass a team through even if it is none. So i just use team = team[0] if teams.count() > 0 else "No team"
I have two django models:
class Order(models.Model):
date = models.DateTimeField()
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='orders')
shipping_address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=9)
comment = models.CharField(max_length=100, blank=True, null=True)
class OrderStatus(models.Model):
STATUS_ACCEPTED = 1
STATUS_PROCESSING = 2
STATUS_DELIVERING = 3
STATUS_COMPLETED = 4
CODE_CHOICES = (
(STATUS_ACCEPTED, 'accepted'),
(STATUS_PROCESSING, 'processing'),
(STATUS_DELIVERING, 'delivering'),
(STATUS_COMPLETED, 'completed'),
)
date_created = models.DateTimeField(auto_now_add=True)
code = models.PositiveSmallIntegerField(choices=CODE_CHOICES)
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='status_list')
Normally if I wanted to get all the orders with 'accepted' status I could write Order.objects.filter(orderstatus__code=1).
But how can I make django admin to create OrderStatus list filter?
I have googled a lot and found only one answer here on stackoverflow, which claims simply adding reverse model ('orderstatus' in my case) to list_filter tuple should work, but I get an error message: The value of 'list_filter[1]' refers to 'orderstatus', which does not refer to a Field.
What am I doing wrong?
Did you try by you self before posting question here, because there are lots of question related to this one, Any way i think this link will help you.
https://books.agiliq.com/projects/django-admin-cookbook/en/latest/many_to_many.html
The value of 'list_filter[1]' refers to 'orderstatus', which does not refer to a Field.
This is because orderstatus is not a field in your model. Either change order field to orderstatus or change the name passed to list_filter to the name of your field.
I have a scenario where in my users profile they have an associated organisation. I need to be able to allow the users to select and set this organisation (user_organization), however I would like to do it without allowing them to just see a list (drop down menu) of all the organisations within the application. My work around for this was to issue each organisation with a unique code (org_code) and allow users to enter that code into a form and have the related organisation applied to their profile. I can easily understand the suedocode logic behind this, however I am unsure how to implement it within my views and forms. If anyone can advise me the best way to do this or point me in the correct direction to learn how? It would be appreciated. See my models below for clarification on how things fit together.
Profile:
class Profile(models.Model):
Super_Admin = "Super_Admin"
Admin = "Admin"
Manager = "Manager"
Developer = "Developer"
ROLE_CHOICES = (
(Super_Admin, 'Super_Admin'),
(Admin, 'Admin'),
(Manager, 'Manager'),
(Developer, 'Developer'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_group = models.OneToOneField(Group, on_delete=models.CASCADE, blank=True, null=True)
user_organization = models.OneToOneField(Organization, on_delete=models.CASCADE, blank=True, null=True)
role = models.CharField(choices=ROLE_CHOICES, default="Developer", max_length=12)
activation_key = models.CharField(max_length=120, blank=True, null=True)
activated = models.BooleanField(default=False)
def __str__(self):
return self.user.username
Organizations:
class Organization(models.Model):
org_name = models.CharField(max_length=120, blank=False, unique=True)
org_code = models.CharField(max_length=120, blank=False, unique=True, default=GenerateOrganozationCode)
Answering using the extra info from the comments you've made above:
"I want them to be able to input a code into a text field which when submitted, if it matches the code (org_code) in the organization model it will then populate the (user_organization) in their Profile with the correct (org_name)"
Within the logic for the view, you need to extract the org_code. You should also make org_code of Organization the primary key of the object (you dont have to, but it would be easier if the pk was the org code). From here, you can map the org_code with the primary key value of Organization.
Organization.objects.get(pk=the_entered_org_code)
If you'd rather not assign org code as the primary key of the object, you can just filter for the org code.
Organization.objects.filter(org_code=the_entered_org_code)
This should get you started.
Firstly, I know how to fix the problem, I'm just trying to understand why it's occuring. The error message:
users.profile: Reverse query name for field 'address' clashes with related field 'Address.profile'. Add a related_name a
rgument to the definition for 'address'.
And the code:
class Address(models.Model):
country = fields.CountryField(default='CA')
province = fields.CAProvinceField()
city = models.CharField(max_length=80)
postal_code = models.CharField(max_length=6)
street1 = models.CharField(max_length=80)
street2 = models.CharField(max_length=80, blank=True, null=True)
street3 = models.CharField(max_length=80, blank=True, null=True)
class Profile(Address):
user = models.ForeignKey(User, unique=True, related_name='profile')
primary_phone = models.CharField(max_length=20)
address = models.ForeignKey(Address, unique=True)
If I understand correctly, this line:
address = models.ForeignKey(Address, unique=True)
Will cause an attribute to be added to the Address class with the name profile. What's creating the other "profile" name?
What if I don't need a reverse name? Is there a way to disable it? Addresses are used for a dozen things, so most of the reverse relationships will be blank anyway.
Is there a way to copy the address fields into the model rather than having a separate table for addresses? Without Python inheritance (this doesn't make sense, and if an Model has 2 addresses, it doesn't work).
in the django docs it says:
If you'd prefer Django didn't create a backwards relation, set related_name to '+'. For example, this will ensure that the User model won't get a backwards relation to this model:
user = models.ForeignKey(User, related_name='+')
but I never tried it myself....
I'm not sure where the errant profile field is coming from… But one way to find out would be: temporary remove address = models.ForeignKey(…) from Profile, ./manage.py shell, from ... import Address then see what Address.profile will tell you.
I don't think there is any official way to inherit only the fields from some other Model without using inheritance… But you could fake it like this (where SourceModel is, eg, Address and TargetModel is, eg, Profile):
for field in SourceModel._meta.fields:
TargetModel.add_to_class(field.name, copy.deepcopy(field))
(this is coming from Django's ModelBase __new__ implementation)
I don't think it's possible to disable the reverse name.
I've just done a quick grep over the code and it doesn't look like there is any logic which will bypass setting up the related_name field on the related model.
For Example: Add just '+'
class GeneralConfiguration(models.Model):
created_at = models.DateTimeField(editable=False, default=settings.DEFAULT_DATE)
updated_at = models.DateTimeField(editable=False, default=settings.DEFAULT_DATE)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='+')
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='+')