Here in my problem, I have a User model, in which a user (login) can be from the “Supplier” company or from “Customer” company.
It is a M2M relationship for both sets of tables: User-Customer and User-Supplier.
Can I link them this way:
company = models.ManyToManyField(Customer, Supplier, on_delete=models.PROTECT, related_name='Users')
enter image description here
Thanks!!
You can't do that.
A better approach will be if you use a Company model with a type of Supplier and Customer you can create an enum for this because you are using the same fields in both of your models so its good to have a type in a single model.
How to make enum in model with TextChoices
Company:
name
address
contact name
type
then in your User model
company = models.ManyToManyField(Company, on_delete=models.PROTECT, related_name='Users')
make more sense this way.
Related
Imagine there are three models named Movie, Actor, and Participation.
class Movie(models.Model):
identifier = models.CharField()
class Actor(models.Model):
name = models.CharField()
class Participation(models.Model):
movie_identifier = models.CharField()
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Let's assume that I can't use ForgeinKey for the movie in the Participation model.
how can I retrieve all the participation records of a movie with only one query?
Here is the solution if I had a foreign key for the movie in the participation table:
qs = Movie.objects.filter(identifier="an_identiier").prefetch_related("participations_set")
How can I do this without having a Movie foreign key in the Participation model?
Thanks!
One of the most important things when designing a database (hence when designing your models) is database normalization [Wikipedia].
You talk about Participation being related to multiple models like Movie, Series, Episode, etc. this means that Movie, Series, Episode all can be said to have something in common or they can be said to be a specialization of another entity let us say Participatable for the lack of a better word, or we can say Participatable is a generalization of Movie, Series, Episode, etc.
How do we model these? Well we will just have an extra model that our other models will have a OneToOneField with:
class Participatable(models.Model):
# Any common fields here
MOVIE = 'M'
SERIES = 'S'
TYPE_CHOICES = [
(MOVIE, 'Movie'),
(SERIES, 'Series'),
]
subject = models.CharField(max_length=1, choices=TYPE_CHOICES)
class Movie(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='movie',
)
class Series(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='series',
)
class Participation(models.Model):
participatable = models.ForgeinKey(Participatable, on_delete=models.CASCADE)
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Other than this solution which I find is the best for such modelling you can go with using the content-types framework which will essentially do what you do currently. That is it will use a field that stores the related id and also a foreign key that points to an entry in a table that will simply describe which table this id is for.
I have the following Models of customer details with each customers having different payment modes (eg. cash, online transfer, etc...) :
class Customer(models.Model):
#some customer details
class Payment(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.RESTRICT, related_name='payments')
payment_mode = models.CharField(max_length=255, blank=True, null=True)
And I would like to add a new Invoice Model to include the customer as well as the customer's payment modes.
class Invoice (models.Model):
customer = models.ForeignKey(Customer, on_delete=models.RESTRICT, related_name='payments')
payment_mode = models.ForeignKey(Customer.payments.payment_mode, on_delete=models.RESTRICT)
I am going to create an Invoice for a customer and will input the customer's available payment mode. But the the invoice's payment mode is giving me an AttributeError: 'ReverseManyToOneDescriptor' object has no attribute 'payment_mode'.
May I know how do I set up the reference to the customer's child data?
Thank you.
What you have is not a valid field definition.
You can reference Payment directly
payment_mode = models.ForeignKey(Payment, on_delete=models.RESTRICT)
Why is the Invoice model even required? You have the same fields already in the existing models.
You can simply make a view to do this.
For example,
def show_invoice(request, pk):
# this pk value should be sent by your frontend and represents your Primary Key value for the current customer
customer = Customer.objects.get(pk=pk)
return render(request, 'some_html_page.html', {'customer': customer})
Now in your some_html_page.html, you can show the details you want using the 'context' to the render function ({'customer': customer}) we just passed.
Models in Django should be thought of as Tables in SQL; you are not supposed to make a new one every time you want to "infer" something, rather you should make them when you want to 'store' something (or normalize existing tables/models). The Invoice model does not do either of these two things.
You can give this a read to understand how to write views in Django this.
In the case where you really want to make an Invoice model you don't need to make a payment_mode field, since you're already pointing to the Customer model which is, in turn, pointing to the Payment model.
I have my model Room as follows:
eid = models.CharField(max_length=64, unique=True)
name = models.CharField(max_length=25)
I want to create another field user where user is a foreign key. Is to possible to create a field where multiple values can be added to a single row? For example: there are 3 users: user1,user2,user3.
Now, I want a row to look like:
{'eid':1,'name':'room1','user':[user1,user2,user3]}
Is the above scenario possible or do I need to create separate rows for each user?
Note: A room model can have multiple users, but a user cannot be part of multiple rooms.
If you want to have multiple foreign keys, you can use ManyToManyField. When you convert it to JSON, it will display as array, just like you wanted.
It looks like a classical many-to-many relationship. As the Django docs say for that case, you could have your model Room as something like this:
eid = models.CharField(max_length=64, unique=True)
name = models.CharField(max_length=25)
users = models.ManyToManyField(User)
EDIT: since the OP has mentioned in a comment that one user must have only one room, but that a room may have many users, then their User model must have a ForeignKey field, as it is a one-to-many relationship:
room = models.ForeignKey(Room, on_delete=models.CASCADE)
Possible values for the on_delete field may be checked in the docs.
I have an external database which I can't modify in any way (read-only). It has three tables - Company (id), CompanyContact (company_id, contact_id), Contact (id, company_id).
Basically, Contact has a nullable foreign-key to Company table and it works as many-to-one, but if company_id is null, I have to look into CompanyContact table, which is many-to-many kind relationship.
How can I combine these two tables (Contact and CompanyContact) into one model - Contact? In other words, how can I get all contacts for a given company?
In SQL that would be something like:
select contact.id from contact where company_id = XXX
union
select contact_id from companycontact where company_id = XXX
Django models:
class Company(models.Model):
uuid = models.CharField(max_length=36, primary_key=True, db_column='id')
class Meta:
managed = False
class Contact(models.Model):
uuid = models.CharField(max_length=36, primary_key=True, db_column='id')
company = models.ForeignKey(Company, db_column='company_id')
class Meta:
managed = False
I don't have a model for CompanyContact. And there is nothing to show in views because that basically is my question, how to get contacts for a given company.
The original tables in your database are not properly structured. It's incorrect that the contact field should have a company_id field. That needlessly complicates all queries (raw SQL or Django) because an additional check is needed on the contact_id field.
On the other hand it's perfectly legit for two entities in a many to many relationship to have exactly one mapping instead of many. So there isn't one clear answer to this question. I suppose your best bet would be to add a ManyToMany field as well. I am making this suggestion purely on the fact that you say the data is read only
class Contact(models.Model):
uuid = models.CharField(max_length=36, primary_key=True, db_column='id')
company = models.ForeignKey(Company, db_column='company_id')
companies = models.ManyToManyField(Company, related_name='companies')
class Meta:
managed = False
I need ot get objects that are foreign keys. Example
class City(models.Model):
.....
class User(models.Model):
city = models.ForeignKeu(City)
.......
Can i get only that cities which are Foreign key to model User with django orm or mysql?
Yes you can, it's all in the Documentation:
https://docs.djangoproject.com/en/1.6/ref/models/querysets/
Provide a readable backward reference to the city model (in your User model change city to this one):
city = models.ForeignKey(City, related_name='user')
Then
cities = City.objects.select_related('user').filter(user__city__isnull=False).all()