Let's say I've got 2 models
class Person(models.Model):
name = models.CharField(max_length=50)
class Language(models.Model):
person = models.ForeignKey(
Person, related_name='prs', on_delete=models.CASCADE)
name = models.CharField(max_length=50)
I want to be able to access all persons languages like that -> person/{person_id}/language
and to access and edit specific language like that -> person/{person_id}/language/{language_id}
In this scenario, you can use drf-nested-routers package.
As you are new to DRF, I know there is chance that you haven't seen routers and ModelViewSet yet, so I would recommend you to go through that first. Here is the link which explains this flow.
Related
I have a Django application where registered users can add, through an input form, details of performances of their music ensemble. This application also has a a section for composers, where they add their own composition. I'm using a custom user model, with profiles linked to user accounts:
class User(AbstractBaseUser):
email = models.EmailField(verbose_name="email", unique=True, max_length=255)
first_name = models.CharField(max_length=30, blank=True, null=True)
[...]
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
[...]
This is my 'composition' model:
class Composition(models.Model):
title = models.CharField(max_length=120) # max_length = required
composer = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
[...]
And this is my 'performance' model. The performance information links to the piece performed (performed):
class Performance(models.Model):
performed = models.ManyToManyField(Composition, blank=True)
[...]
So far, so good. Now, I'd like the performers to be able to add pieces by composers who are not (yet) registered to the website. Let's say that the performer performed a piece by John Lennon and is adding information about that performance. So, the performer will need to be able to add both John Lennon, his composition, and link the two.
The most important bit is: if the ghost of John Lennon tomorrow wants to register to the website, the administrator of the website will need to be able to easily link the compositions already added by the performers to John Lennon's newly created account. Is that possible? I suppose the key to solving this issue is changing composer = models.ForeignKey(settings.AUTH_USER_MODEL... with something else, i.e. using a intermediary model. Any suggestion will be greatly appreciated.
There are different ways to do this, you should choose one based on your taste:
When you know that the actual user is registered, just delete the old, fake user referred in the composition and replace it with the actual user.
Create a new model named something like Artist and change the composer relationship to refer to the Artist model. then, link the Artist model to the actual user with a nullable foreign key.
First of all I have to admit that I'm quite new to all this coding stuff but as I couldn't find a proper solution doing it myself and learning to code is probably the best way.
Anyway, I'm trying to build an app to show different titleholders, championships and stuff like that. After reading the Django documentation I figured out I have to use intermediate models as a better way. My old models.py looks like this:
class Person(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
[...]
class Team(models.Model):
name = models.CharField(max_length=64)
team_member_one = models.ForeignKey(Person)
team_member_two = models.ForeignKey(Person)
class Championship(models.Model):
name = models.CharField(max_length=128)
status = models.BooleanField(default=True)
class Titleholder(models.Model):
championship = models.ForeignKey(Championship)
date_won = models.DateField(null=True,blank=True)
date_lost = models.DateField(null=True,blank=True)
titleholder_one = models.ForeignKey(Person,related_name='titleholder_one',null=True,blank=True)
titleholder_two = models.ForeignKey(Person,related_name='titleholder_two',null=True,blank=True)
Championships can be won by either individuals or teams, depending if it's a singles or team championship, that's why I had to foreign keys in the Titleholder class. Looking at the Django documentation this just seems false. On the other hand, for me as a beginner, the intermediate model in the example just doesn't seem to fit my model in any way.
Long story short: can anyone point me in the right direction on how to build the model the right way? Note: this is merely a question on how to build the models and displaying it in the Django admin, I don't even talk about building the templates as of now.
Help would be greatly appreciated! Thanks in advance guys.
So I will take it up from scratch. You seem to be somewhat new to E-R Database Modelling. If I was trying to do what you do, I would create my models the following way.
Firstly, Team would've been my "corner" model (I use this term to mean models that do not have any FK fields), and then Person model would come into play as follows.
class Team(models.Model):
name = models.CharField(max_length=64)
class Person(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
team = models.ForeignKey(to=Team, null=True, blank=True, related_name='members')
This effectively makes the models scalable, and even if you are never going to have more than two people in a team, this is good practice.
Next comes the Championship model. I would connect this model directly with the Person model as a many-to-many relationship with a 'through' model as follows.
class Championship(models.Model):
name = models.CharField(max_length=64)
status = models.BooleanField(default=False) # This is not a great name for a field. I think should be more meaningful.
winners = models.ManyToManyField(to=Person, related_name='championships', through='Title')
class Title(models.Model):
championship = models.ForeignKey(to=Championship, related_name='titles')
winner = models.ForeignKey(to=Person, related_name='titles')
date = models.DateField(null=True, blank=True)
This is just the way I would've done it, based on what I understood. I am sure I did not understand everything that you're trying to do. As my understanding changes, I might modify these models to suit my need.
Another approach that can be taken is by using a GenericForeignKey field to create a field that could be a FK to either the Team model or the Person model. Or another thing that can be changed could be you adding another model to hold details of each time a championship has been held. There are many ways to go about it, and no one correct way.
Let me know if you have any questions, or anything I haven't dealt with. I will try and modify the answer as per the need.
Just starting in Python/Django framework so sorry if this is dumb... but i cant find any solution.
class Dealer(models.Model):
name = models.CharField(max_length=200)
contacts = models.ManyToManyField(Contact)
class Contact(models.Model):
name = models.CharField(max_length=200)
dealers = models.ManyToManyField(Dealer)
I have this relation set up however when I run SyncDB it doesnt work. It tells me that Contact is not defined on this line
contacts = models.ManyToManyField(Contact)
Im more familiar with compiled languages. Is there anyway to tell python that the contact class exists, or better yet is there a special syntax im missing for defining this kind of relation.
I dont see a need for a two way ManyToMany in both the models, as they are a M:N relationship (2 way relationship).
Your issue here is, Contact is not defined at the point of execution of this code:
contacts = models.ManyToManyField(Contact)
So You need to wrap it in quotes for it to work
contacts = models.ManyToManyField('Contact')
Documentation on that can be found here
I would recommend the following models:
class Dealer(models.Model):
name = models.CharField(max_length=200)
contacts = models.ManyToManyField('Contact')
class Contact(models.Model):
name = models.CharField(max_length=200)
and It would do exactly what you are looking for.
You can read about ManyToMany relationships here. The same link also covers how to handle Reverse m2m queries
If you want to do a two way ManyToMany both, you just only need to do this:
class Dealer(models.Model):
name = models.CharField(max_length=200)
contacts = models.ManyToManyField('Contact', blank=True)
class Contact(models.Model):
name = models.CharField(max_length=200)
dealers = models.ManyToManyField('Dealer', through=Dealer.projects.through, blank=True)
I guess it will work to you.
I'm trying to use the Django REST framework to generate json I'll be able to use later on my website. The thing is, I have Users, who have one-to-many projects, and these projects have one-to-many tasks.
The thing is, I'd like to display a list of my users, then when I access the details of an user, I can see his projects. Then, when I check the details of a project, I can see the tasks of this project. Now, my models are defined like this :
class SimpleUser(AbstractBaseUser):
username = models.TextField(max_length=40, unique=True)
firstname = models.TextField(max_length=40)
lastname = models.TextField(max_length=40)
class Project(models.Model):
user = models.ForeignKey(SimpleUser, null=True)
name = models.TextField(max_length=255)
class Task(models.Model):
project = models.ForeignKey(Project, related_name='task_project')
title = models.TextField(max_length=255)
And when I'm trying to display for example the Projects linked to an User, I have an error no matter what I try (I'm pretty sure this is because what I do is wrong), and the error is "SimpleUser has no attribute Project". Which is logical. But I really don't know how to do this, can someone help me ?
You should use project_set to access SimpleUsers Projects.
user = SimpleUser.objects.get(id=1)
projects = user.project_set.all()
Or define a specific name for the manager with related_name=:
user = models.ForeignKey(SimpleUser, null=True, related_name='projects')
Then you can access users projects via projects:
projects = user.projects.all()
Try specifying explicitly the related_name for the relationship:
class Project(models.Model):
user = models.ForeignKey(SimpleUser, null=True, related_name='projects')
name = models.TextField(max_length=255)
If I had a One-To-Many relationship in Django, like the Django example at http://docs.djangoproject.com/en/dev/topics/db/models/#fields, A musician can have many albums, unique to that musician.
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
How would I go about implementing the following:
In Django, have 'Musicians' as a section to manage. When you go to manage musicians, you can edit the musician, or you can go on to the albums and manage the albums only for that musician. When you make a new album, the system automatically creates it for the musician you are on.
At the moment, you would have to manage albums individually from a huge list and choose the musician in the edit screen.
This is too complicated for the django admin as is, so either you explore the customization that the docs offers for you or you might consider not using the django admin at all and just write it as a part of your web app.
Check out http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adminsite-objects.
Admin inlines is one solution - http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects - this will allow you to edit any Albums associated with the musician you are viewing or add a new one.