Let's say you've got a ActiveDirectoryUser model:
class ActiveDirectoryUser(models.Model):
object_guid = models.CharField(max_length=200, unique=True)
mail = models.EmailField(unique=True)
name = models.CharField(max_length=200)
This model is populated from an Active Directory query. Every day, I rerun a job in batch that queries Active Directory, gets the results back, and checks if the person is already in AD. If they are it checks if anything has changed, and if not they get added to the Database. I found myself writing:
try:
ad_user = ActiveDirectoryUser.objects.get(object_guid=object_guid)
ad_user.object_guid = object_guid
ad_user.mail = mail
ad_user.name = name
ad_user.save()
except ActiveDirectoryUser.DoesNotExist:
ActiveDirectoryUser(
object_guid=object_guid,
mail=mail,
name=name).save()
Basically, I try to get the object with the attributes and if that throws a DoesNotExist exception, I know it's not already there and so I create a new one. Is this the right/best/idiomatic way of either updating or saving a new object into the database? I know it works, but it looks wrong somehow. Inelegant.
No, django has a built-in way to do this.
entry, created = ActiveDirectory.objects.get_or_create(
object_guid = 'your_value',
name = = 'your_value',
mail = 'your_value'
)
Related
There are such models:
class Nomenclature(models.Model):
nameNom = models.CharField(max_length=150,verbose_name = "Название номеклатуры")
numNom = models.CharField(max_length=50,verbose_name = "Номер номеклатуры",unique=True)
quantity = models.IntegerField(verbose_name="Количество", default=0)
numPolk = models.CharField(max_length=150,verbose_name = "Номер полки/места"
class Changes(models.Model):
numNomenclature = models.ForeignKey(Nomenclature, on_delete=models.CASCADE,related_name="chamges",verbose_name="Номер номеклатуры")
quantity = models.IntegerField(verbose_name="Количество",null=True)
location = models.CharField(max_length=50,verbose_name = "Место установки")
fullname = models.CharField(max_length=150,verbose_name = "ФИО")
appointment = models.CharField(max_length=50,verbose_name = "Назначение")
created_at = models.DateTimeField(auto_now_add=True,verbose_name='Дата/время', null=True)
It is necessary to output the name and number of the nomenclature and all related changes to the template, and also output all fields
I found that select_related exists, but I thought that it doesn't work the way I need it to.
I'm not completely sure if this is what you need.
If you need to fetch all of the changes, from a single "Nomenclature" model:
md = Nomenclature.objects.get(id=id) # Not sure how you fetch this, just an example.
all_changes_for_md = Changes.objects.filter(numNomenclature__id=md.id)
This will fetch you all changes for a nomenclature model.
Also possible to do it like this:
md = Nomenclature.objects.get(id=id) # Not sure how you fetch this, just an example.
all_changes_for_md = md.chamges.all() # You made a typo in the related name.
Select related has another purpose, it is used for prefetching.
From the Django docs:
select_related(*fields)
Returns a QuerySet that will “follow” foreign-key relationships, selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won’t require database queries.
https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-related
So this seems to be asked before but for the life of me, i cannot get any of the solutions to work.
I have two classes, Device and Log. There are many logs per device and i'd like to be able to add new items to the Log objects.
class Device(models.Models):
name = models.Charfield(max_length=100)
type = models.Charfield(max_length=100)
class Log(models.Modles):
device = models.ForeignKey(Device, related_name='msgs', on_delete=models.CASCADE)
log = models.Charfield(max_length=100)
date_time = models.DateTimeField(auto_now=True)
I've been trying things like this in my view:
device = Device.objects.filter(name=hostname)
device.msgs.add(log=new_log_msg)
but nothing i try is working. any ideas?
You need a Device instance, but filter always gives a queryset. You should use get.
device = Device.objects.get(name=hostname)
device.msgs.add(log=new_log_msg)
Get device object as
device = Device.objects.filter(name=hostname) # If hostname not found throw exception
For creating a new log
log = Log.objects.create(device=device, log='')
use get instead of filter in queryset and for creating and updating the alway intitiate the instance.
device = Device.objects.get(name=hostname)
device.msgs.add(log=new_log_msg)
For adding data in log
Log.objects.create(device=device, log='')
The device=device is foriegn key.
I have a couple of Django model questions. I am running the following code as a Django manage extension, which I am new to.
1) I am not certain my "Location.objects.get(city=key)" is correct for OneToMany in my add_server_to_db function. I suspect this is incorrect?
2) How can I harden this so if this is executed twice, it will update existing Server entries vs. error out?
Django Server Model:
class Servers(models.Model):
name = models.CharField(('name'), max_length=128)
location = models.OneToOneField('locations.Location', on_delete=models.CASCADE)
ip_address = models.CharField(('ip_address'), max_length=128)
date = models.DateField(auto_now=True)
Django Location Model:
class Location(models.Model):
city = models.CharField(('city'), max_length=10)
geolocation = models.PointField(('location'))
Function:
def add_server_to_db(data_dict):
print(data_dict)
for key, val in data_dict.items():
loc = Location.objects.get(city=key)
m = Server(
location=loc,
name=val['name'],
ip_address=val['ip_address'],
m.save()
Thanks.
I don't understand your question 1; there's nothing wrong with that line, and nothing specific to "one-to-many" in any case.
To prevent this creating new entries every time, you should use update_or_create:
loc = Location.objects.get(city=key)
Server.objects.update_or_create(
location=loc,
defaults={'name': val['name'], 'ip_address': val['ip_address']}
)
There's no need to call save() after this.
I have two models that I'm relating using Django's OneToOneField, following this documentation: https://docs.djangoproject.com/en/2.0/topics/db/examples/one_to_one/
class Seats(models.Model):
north = models.OneToOneField('User',on_delete=models.CASCADE,related_name='north', default=None, null=True)
bridgetable = models.OneToOneField('BridgeTable',on_delete=models.CASCADE, default=None, null=True)
class BridgeTableManager(models.Manager):
def create_deal(self):
deal = construct_deal()
table = self.create(deal=deal)
s = Seats(bridgetable=table)
s.save()
return table
class BridgeTable(models.Model):
deal = DealField(default=None,null=True)
When I run this code I can successfully get the relationship working
table = BridgeTable.objects.get(pk='1')
user = User.objects.get(username=username)
table.seats.north = user
table.seats.north.save()
print(table.seats.north)
The print statement prints out the name of the player sitting north. But if I try to access the table again like this:
table = BridgeTable.objects.get(pk='1')
print(table.seats.north)
I get "None" instead of the user's name. Is there something I'm missing, like a save that I missed or some concept I'm not understanding? Thanks.
You should save Seats model object that is table.seats.save()
Try print table.seats.north
While table.seats.north.save() runs save on User object
Here are correct steps:
table = BridgeTable.objects.get(pk='1')
user = User.objects.get(username=username)
table.seats.north = user
table.seats.save()
print(table.seats.north)
I am working with django and having a hard time grasping how to do complex queries
Here is my model
class TankJournal(models.Model):
user = models.ForeignKey(User)
tank = models.ForeignKey(TankProfile)
ts = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=50)
body = models.TextField()
class Meta:
ordering = ('-ts',)
get_latest_by = 'ts'
I need to pull the username given the tank object.
The user object is the one built into django.. thanks!
EDIT:
I have tried this
print User.objects.filter(tankjournal__tank__exact=id)
It seems to not pull out just the id.. and pull out everything in tankjournal and match it to the tank object
If you already have your tank object you should be able to do:
tank.user.username
To reduce the database queries you might want to consider the use of select_related(), e.g.
tanks = TankJournal.objects.all().select_related()
for tank in tanks:
username = tank.user.username
if you have a specific tank id then:
tank = TankJournal.objects.select_related().get(id=123456)
username = tank.user.username
I may be misunderstanding your question, but a request on User.objects.filter() will return a list of User objects, not User ids. What you've written looks technically correct.
Remember, though, that the model you have sets up a one-to-many between the TankProfile object and the TankJournal. In other words, a single TankProfile can be associated with more than one TankJournal, and therefore to more than one user. Given this, you're query is doing the right thing, returning more than one User.