I have a robot model, like:
class Robot(models.Model):
version = models.CharField(max_length=20)
can_version = models.CharField(max_length=20)
uuid = models.CharField(max_length=20)
power_status = models.PositiveSmallIntegerField(choices=POWER_STATUS)
working_status = models.PositiveSmallIntegerField(choices=WORKING_STATUS)
I want to save the current state(all fields) of a robot into database when an error occurs, because I need these information to analyse the cause of error, and querying these information is a frequent operation.
Model audit is not what I want, for I need not to save the whole change history, but only the instantaneous state when error happens. I don't want to create a new model which duplicate all Robot fields and used to save Robot state either.
It sounds like status should be a seperate model/class with an FK to the robot, that way your robot has a "list" of all of its previous status' and you just need to query the latest.
class ModelStatus(models.Model):
robot = models.ForeignKey(Robot)
power_status = models.PositiveSmallIntegerField(choices=POWER_STATUS)
working_status = models.PositiveSmallIntegerField(choices=WORKING_STATUS)
You may want to add someway to order them other than the id but thats a decision I can't really help you with.
If you don't want the whole list then you can just have two OneToOneFields on your Robot
current_status = models.OneToOneField(ModelStatus, null=True)
previous_status = models.OneToOneField(ModelStatus, null=True)
Related
I have the following in my model:
class Genre(models.Model):
name = models.CharField(max_length=100)
def my_latest_song(self):
song = Song.objects.filter(genre_id=self.id, author_id=XXXXXXXXX).order_by('-date')
return song[0];
class Song(models.Model):
name = models.CharField(max_length=100)
genre = models.ForeignKey(Genre, on_delete=models.CASCADE, null=True)
date = models.DateField()
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
So with the my_latest_song method I want to obtain for each genre what the latest song is for the user currently logged in. Note: I am already making sure that users MUST be logged in to see this, do not worry about this additional validation.
The question is: how can I pass the user id of the user that is currently logged in onto this model method? Where the XXXXXXXXXX is listed I have tried:
author_id=request.user.id
author_id=user.id
author=request.user
author=user
And many similar options. But I'm new to Django and just not sure about how to properly reference this. Nothing is working yet.
Please note: the issue is that I am constantly (in many different views) displaying the latest song for each genre. So that's why I am thinking it makes sense in the model. It's not stored in a database, it's simply retrieved within the model. Please let me know if this is not appropriate.
For instance, on many pages I am showing a list of genres and for each genre the latest song uploaded by that user:
Genre | Last Song
----------------------
Pop | Song 1
Rock | Song 33
Classic | Song 32
Something like this maybe?
...
def my_latest_song(self, user_id):
song = Song.objects.filter(genre_id=self.id, author=User.objects.get(pk=user_id)).order_by('date')
return song[0];
...
You will not be able to use request.user.id or any other request value in that method, as the model does not actually use requests. That usually is done by a form.
You should not be making this query in your model. It is much better to make the query in views.py whenever you need the information.
Below is, if I understand correctly, what you would need to do to make this query in the view.
def relevant_view(request,genreID_from_url):
# ... #
song = Song.objects.filter(author=request.user).filter(genre=genreID_from_url).order_by('-date')[:1]
# ... #
A couple of points:
I think you would need to pass the genre you are querying for in the URL. Here is a good tutorial for that: http://django-book.readthedocs.io/en/latest/chapter03.html#your-third-view-dynamic-urls . You could also do it using a form - it depends on the circumstances in which the query needs to be made.
You need to order by '-date' and not 'date' so that you get the most recent song at the start of the query.
The [ ] at the end is Django's syntax for limiting a queryset. The above limits it to only the first item of the queryset, as you are attempting to do.
The page in the Django docs for queries is really helpful and clear: https://docs.djangoproject.com/en/2.0/topics/db/queries/
So this is more of a conceptual question, and I am really looking for someone to just help point me in the right direction. I am building a middleware platform where I will be pull data in from inbound channels, manipulating it, and then pushing it out the other door to outbound channels. I will need to store the external id for each of these records, but the kicker is, records will be pulled from multiple sources, and then pushed to multiple sources. A single record in my system will need to be tied to any number of external ids.
a quick model to work with:
class record(models.Model):
#id
Name = models.CharField(max_length=255, help_text="")
Description = models.CharField(max_length=255, help_text="")
category_id = model.ForeignKey(category)
class category(models.Model):
#id
name = models.CharField(max_length=255, help_text="")
description = models.CharField(max_length=255, help_text="")
class channel(models.Model):
#id
name = models.CharField(max_length=255, help_text="")
inbound = models.BooleanField()
outbound = models.BooleanField()
Obviously, I cannot add a new field to every model every time I add a new integration, that would be soooo 90s. The obvious would be to create another model to simply store the channel and record id with the unique id, and maybe this is the answer.
class external_ref(models.Model):
model_name = models.CharfieldField()
internal_id = models.IntegerField()
external_id = models.IntegerField()
channel_id = models.IntegerField()
class Meta:
unique_together = ('model', 'internal_id',)
While my example holds simply 4 models, I will be integrating records from 10-20 different models, so something I could implement an a global level would be optimal. Other things I have considered:
Overwriting the base model class to create a new "parent" class that also holds an alpha-numberic representation of every record in the db as unique.
Creating an abstract model to do the same.
Possibly storing a json reference with channel : external_id that I could ping on every record to see if it has an external reference.
I'm really an open book on this, and the internet has become increasingly overwhelming to sift through. Any best practices or advice would be much appreciated. Thanks in advance.
I have this exact issue and yes there is not much information on the web in using Django this way. Heres what Im doing - haven't used it long enough to determine if its "the best" way.
I have a class IngestedModel which tracks the source of the incoming objects as well as their external ids. This is also where you would put a unique_together constraint (on external_id and source)
class RawObject(TimeStampedModel):
"""
A Table to keep track of all objects ingested into the database and where they came from
"""
data = models.JSONField()
source = models.ForeignKey(Source,on_delete=models.PROTECT)
class IngestedModel(models.Model):
external_id = models.CharField(max_length=50)
source = models.ForeignKey(Source,on_delete=models.CASCADE)# 1 or 0
raw_objects = models.ManyToManyField(RawObject,blank=True)
class Meta:
abstract = True
then every model that is created from ingested data inherits from this IngestedModel. That way you know its source and you can use each external object for more than 1 internal object and vise versa.
class Customer(IngesteModel):
class Order(IngestedModel):
...
etc.
Now this means there is no "IngestedModel" table but that every model has a field for source, external_id and a reference to a raw object (many to many). This feels more compositional rather than inherited - no child tables which seems better to me. I would also love to hear feedback on the "right" way to do this.
I am trying to build a tool that, at a simple level, tries to analyse how to buy a flat. DB = POSTGRES
So the model basically is:
class Property(models.Model):
address = CharField(max_length = 200)
price = IntegerField()
user = ForeignKey(User) # user who entered the property in the database
#..
#..
# some more fields that are common across all flats
#However, users might have their own way of analysing
# one user might want to put
estimated_price = IntegerField() # his own estimate of the price, different from the zoopla or rightmove listing price
time_to_purchase = IntegerField() # his own estimate on how long it will take to purchase
# another user might want to put other fields
# might be his purchase process requires sorting or filtering based on these two fields
number_of_bedrooms = IntegerField()
previous_owner_name = CharField()
How do I give such flexiblity to users? They should be able to sort , filter and query their own rows (in the Property table) by these custom fields. The only option I can think of now is the JSONField Postgres field
Any advice? I am surprised this is not solved readily in Django - I am sure lots of other people would have come across this problem already
Thanks
Edit: As the comments point out. JSON field is a better idea in this case.
Simple. Use Relations.
Create a model called attributes.
It will have a foreign key to a Property, a name field and a value field.
Something like,
class Attribute(models.Model):
property = models.ForiegnKey(Property)
name = models.CharField(max_length=50)
value = models.CharField(max_length=150)
Create an object each for all custom attributes of a property.
When using database queries use select_related of prefetch_related for faster response, less db operations.
EDIT: Given responses in comments and answer I tried suggestion and I get some errors when trying to query , also doing the related name query does not get the right results (as seen in comments)
BusinessLocations.objects.all()
Error: QuerySet object has no attribute 'objects' is the error.
In either case, I did a dump of all the tables and see this:
auth_business_permissions', u'auth_permission', u'auth_user', u'auth_user_businesss', u'auth_user_user_permissions', u'django_admin_log',
u'django_content_type', u'django_migrations', u'django_session', u'ipaswdb_address', u'ipaswdb_billing', u'ipaswdb_billing_businesss',
u'ipaswdb_designation', u'ipaswdb_business', u'ipaswdb_business_business_locations', u'ipaswdb_businessinsurances', u'ipaswdb_businessinvoices',
'ipaswdb_businesslocations', u'ipaswdb_businessterm', u'ipaswdb_insurance', u'ipaswdb_insurance_businesss', u'ipaswdb_invoice', u'ipaswdb_employee',
u'ipaswdb_employeeinvoice', u'ipaswdb_employeelocations', u'ipaswdb_employeeterms', u'ipaswdb_specialty']
I have a ipaswdb_business_business_locations and a ipaswdb_businesslocations which seems strange to me, and I wonder if my database is just gunked up?
Original Question:
I have two models a Business and an Employee. I want them both to be aware of each other but not directly but through another model called a 'BusinessesLocation`. I can sort of express this in my models but it doesn't look or feel right. It is like only the employee knows of the businesses, and not vice vice versa.
I had another question opened to try to answer this but the answer was not 100% correct in that it didn't offer for a many to many it was more like a one to many. In this case: An employee can work at many locations (potentially being an employee of many businesses) and a business can have many locations having many employees.
Currently my models work where this shell script works:
someEmployee.business_locations.all()[0].business.business_name
and it works fine, I can get all the locations of a business an employee works at and via that infer the many businesses an employee might work for given the businesses locations.
But I cannot figure out how to go the other way, and find out all the employees a business has working for them and at which locations
My current (wrongish) models are like this:
class Employee(models.Model):
first_name = models.CharField(max_length = 50)
business_locations = models.ManyToManyField('BusinessLocations', through='EmployeeLocations')
class EmployeeLocations(models.Model):
employee = models.ForeignKey('Employee', on_delete=models.CASCADE)
business_location = models.ForeignKey('BusinessLocations', on_delete=models.CASCADE)
created_at=models.DateField(auto_now_add=True)
updated_at=models.DateField(auto_now=True)
def __str__(self):
return self.provider.first_name
class BusinessLocations(models.Model):
address = models.ForeignKey('Address', on_delete= models.SET_NULL, null=True)
business = models.ForeignKey('Business', on_delete=models.CASCADE)
doing_business_as = models.CharField(max_length = 255)
created_at=models.DateField(auto_now_add=True)
updated_at=models.DateField(auto_now=True)
def __str__(self):
return self.doing_business_as
class Business(models.Model):
business_name = models.CharField(max_length=50)
business_locations = I need something here no idea how
Bellow is some pseudo shell code demonstrating how I would like my models to work:
#create a new business location assume business has been created
newLocation = Address(...)
business.business_locations.add(newLocation, doing_business_as='alternative name maybe')
#assume employee exists
#add a new business location to the employee
#when i say selected business the form would have current employee then in its locations
#you'd have to select a business first, and get a list of all that businesses locations and you
#you could add the business location and then select another business with all ITS locations
# and add one there too if you wish
employee.employee_locations.add(selectedBusiness.business_locations[0])
employee.employee_locations.add(anotherSelectedBusiness.business_locations[1])
Below is what I cannot figure out how to do, vice versa...
#now lets see which businesses the employee works for.
for business in employee.business_locations
business.business_name
#and lets see each businesses employees:
for employee in Employee.objects.all()
employee.
?? No idea how to build the models to represent these relationships
I can get an employees business locations just fine, but I cannot get the above examples of getting a list of employees for a business. Not sure what I need to adjust (or methods I might need?) to get this to work like I want in my shell example.
What you're missing is Django's concept of related objects.
When you define a relationship in a model (i.e., a ForeignKey, OneToOneField, or ManyToManyField), instances of that model will have a convenient API to access the related objects.
You can access the related objects both in queries and as a manager attribute on your models. See the examples in the documentation. In your case this would look something like:
# Now lets see which businesses the employee works for:
Business.objects.filter(businesslocations__employee=employee).distinct()
# And let's see each business's employees:
Employee.objects.filter(business_locations__business=business).distinct()
I read this page but didn't get when to use embedding feature and when to use linking.I have a project in django for which I am using MongoDB.In my models.py file I have following models:
class Projects(models.Model):
projectName =models.CharField(max_length = 100,unique=True,db_index=True)
projectManager = EmbeddedModelField('Users')
class Teams(models.Model):
teamType = models.CharField(max_length =100)
teamLeader = EmbeddedModelField('Users')
teamProject = EmbeddedModelField('Projects')
objects = MongoDBManager()
class Users(models.Model):
name = models.CharField(max_length = 100,unique=True)
designation = models.CharField(max_length =100 )
teams = ListField(EmbeddedModelField('Teams'))
class Tasks(models.Model):
title = models.CharField(max_length = 150)
description = models.CharField(max_length=1000)
priority = models.CharField(max_length=20)
Status = models.CharField(max_length=20)
assigned_to = EmbeddedModelField('Users')
assigned_by = EmbeddedModelField('Users')
child_tasks = ListField()
parent_task = models.CharField(max_length = 150)
My question is if we do embedding do we have to update the object in all models.Like if I want to update the name of a 'user' ,I would have to run update for models:Projects, Teams, Users and Tasks or linking would be better in my case?
In your example, yes, changing the name of a user implies that if you use embedding then you must update all other documents with an extra step. What is more appropriate in your situation is linking (referencing). This involves an extra step at query time, but because of your particular "business logic", it is better.
Generally, if a given document needs to be accessed from a number of different places then it makes sense to make it a reference rather than embedded. The same applies in situations when a document changes frequently.
First, conceptually, name your model classes as singular objects.
Users should be User, Teams should be Team...
Think of the model as the mold from which multiple objects will be made. User model will product Users and be stored in a table called Users where each document/row is a User object.
Now, regarding your question, hymloth is exactly right. The way to make it a reference to a document instead of an embedded one is to change those particular fields to reference the id of a user in the user's collection. That way you are just storing an id to lookup instead of a copy of the user document. When you change the reference document, it will be changed in all of the places it is referenced as well. (Typical relational association)
I didn't see a field for that in Django-mongoDB either but maybe you can use the traditional django ForeignKey field for this purpose. I don't know if you can mix and match so give it a shot.
for example, your Teams class would have a field like this:
teamLeader = ForeignKey(User)
Let me know if that works.