This a question from a Django noob, my question goes thus;
What is the difference between a normal foreignkey and a reverse relation and what is the difference. I always thought;
method 1
class State(models.Model):
name = models.CharField()
class Country(models.Model):
name = models.CharField()
state = models.ForeignKey(State) # normal foreignkey
method 2
class Country(models.Model):
name = models.CharField()
class State(models.Model):
name = models.ForeignKey(Country) # reverse relation
What is the main difference between method 1 and 2 and when to use it.
This is basically a database related question and I encourage you to read further about it.
a Foreign key relationship in Django translates to 1 to many relationship in database design.
In your example and real world 1 state can have 1 country and one country only.
But a Country can have infinite (or n) number of states.
So in our country model we can't have infinite fields to represent all the states.
What we can do is we tell each state that which country they belong to.
so this is the right way to do it here.
class Country(models.Model):
name = models.CharField()
class State(models.Model):
name = models.CharField()
country = models.ForeignKey(Country)
In the first method that you wrote each country can have 1 state but each state can belong to multiple countries.
Related
models.py :
class Employee(models.Model):
name = models.CharField(max_length=100)
class Department(models.Model):
name = models.CharField(max_length=100)
employee = models.ManyToManyField(Employee, null=True, blank=True)
I need to save employee ids (instead of employee object) in 'employee' ManyToManyField of 'Department' model. How to do that?
views.py:
dept = Department(name=name)
dept.save()
employee_ids = [1,2]
We can use method add (Django Docs):
Adds the specified model objects to the related object set.
dept = Department.objects.create(name=name)
dept.employee.add(*[1, 2])
Or method set(Django Docs):
Replace the set of related objects
dept.employee.set([1, 2])
Note that add(), create(), remove(), clear(), and set() all
apply database changes immediately for all types of related fields. In
other words, there is no need to call save() on either end of the
relationship.
I think this question is unclear what exactly are you trying to do ?
If you want to create a relation between department and employee on the database level django does that for you
on your current structure the relation and is like
id|department_id|user_id
--|-------------|-------
1| 3 | 2
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 created a model called Department, Course. Models are as follow
This is the model for departments and course
class Departments(models.Model):
Department_Id = models.IntegerField(primary_key=True)
Department_Name = models.CharField(max_length=200)
Department_Code = models.CharField(max_length=200)
class Course(models.Model):
Course_Id = models.IntegerField(primary_key=True)
Department_Id = models.ForeignKey(Departments, on_delete=models.CASCADE)
Course_Name = models.CharField(max_length=200)
Course_Code = models.CharField(max_length=200)
I want to create a model called view which can be later on called for search. I want a view model in a such a way that it consit of the data in concat form i.e. name= Department_name+ Course_Name
class View (models.model):
view_id= models.IntegerField(primary_key=True)
Name= Department_name(I want this from Departments table)
+ Course_Name(I want this from Course table)
I try using one to one relation . I would really appricate the help
It's not clear why you'd want to do that. It's never a good idea to duplicate data from one model into another one, as it can lead to inconsistencies.
You can add a ForeignKey in View to your Course model and then when you do f"{view.course.name} {view.course.department.name}" you already have your string:
class View(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
def name(self):
return f"{self.course.name} {self.course.department.name}"
Notes:
Don't call your foreign key Department_id because it's not referring to the id but to the object itself in the Django ORM: department = models.ForeignKey(Department, on_delete=models.CASCADE). As you can see, this makes reading the code much simpler: self.course.Department_id is a Department object not an integer, so self.course.department makes more sense.
Don't prefix your field names with the class, it just makes the code so much less readable: Do you prefer department.name or department.Department_name?
The View model is still a mystery to me, as you can search without it. You can search for example for courses with a matching department name like this:
Course.objects.filter(department__name__icontains="maths")
which will return all courses with "maths" in their department name.
Remove all the ids from your models, they are created automatically by Django anyway (and called id). Again, department.id is much easier to read than department.Department_id. Also in your code, you have to generate the ids yourself since you don't set them to auto-populate.
I have three models for countries, provinces and cities. one of URLs includes the city name where a post should go. I could get the name of the city through the URL . In view function, I could find the city name and then I could find the country which the city is belong to. Now, I want to list all cities under this country. My question is how can I do this where there is no direct relation between city and country. The city is related to the province and the province related to the country. The list I want should includes all cities inside the country regardless of the province. How can I do this? is there any possible solution rather than make direct relation between city and country model?
Note: I could get the country ID through the variable post_city. The country ID for selected city was 3. Therefor, I want all of cities that are under the country that has an ID of 3.
Example: through the URL: I got post_city variable as Los Angeles. Hence, I want all cities in the USA regardless of state of California. Another example, If the post_city variable was London, then, I want all cities in Britain regardless of the province.
the models I have are as follow:
class Country(models.Model):
country_name = models.CharField(max_length=64, unique=True)
def __str__(self):
return "%s" % (self.country_name)
class Province(models.Model):
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
province_name = models.CharField(max_length=64)
def __str__(self):
return "%s" % (self.province_name)
class City(models.Model):
province_name = models.ForeignKey(Province, on_delete=models.CASCADE)
city_name = models.CharField(max_length=64)
def Country(self):
return self.province_name.country_id.country_name
the view function as follow:
def list_page(request, post_city):
p_c = City.objects.filter(city_name__iexact=post_city).get()
p_p = p_c.province_name
p_country = p_p.country_id
pp=City.objects.all()
print(pp)
context = {
'post_city' : post_city,
'all_p_cities': all_p_cities,
}
return render(request, 'path/to/list_page.html', context )
You can chain multiple related model lookups by using several __ parts in the lookup argument name.
cities_in_narnia = City.objects.filter(province_name__country_id__country_name='Narnia')
Read more in the Django docs: Lookups that span relationships
As a side note. There are some naming conventions you can use that will make your code more readable, especially when seeking help from the online community.
class City(models.Model):
# foreign key fields should be the snake_case or lower case name of the related model class
province = models.ForeignKey(Province, on_delete=models.CASCADE)
# there's no need to prefix field or attribute names with the class name
# City.city_name is superfluous. City.name is perfectly clear.
name = models.CharField(max_length=64)
# methods and attributes should also be snake_case, only use CapitalCase for class names.
#property
def country_name(self):
return self.province.country.name
If you follow these naming conventions, the filter lookup will also be readable and concise.
cities_in_narnia = City.objects.filter(province__country__name='Narnia')
models.py
class City(models.Model):
name = models.CharField()
class Place(models.Model):
name = models.CharField()
city = models.ForeignKey()
Say an instance of a city has 50 places. What would be the simplest approach to serializing those city objects and including the place count as property in the serialization
json = serialize('json', City.objects.all())
I've tried multiple things but they all start getting really messy at one point or another and I've yet to get one to work