Django model relates to two other models - django

I'm trying to build a dictionary application and having a difficulty with the model.
Now I wrote this
class Term(models.Model):
term_text = models.CharField("phrase term text", max_length=100)
class Definition(models.Model):
term = models.ForeignKey(Term)
definition_text = models.TextField()
class Country(models.Model):
#is this correct method?
#Should i add ForeginKey for both Term and Definition here?
The problem is the Country. Both Term and Definition should have a Country field as Term could be available in many countries and a definition could be limited to certain countries with another definition for others.
now how to do this country model?
I've tried to use django-countries as a model field for Term and Definition but its limiting me to use only 1 country per object.

What you want is ManyToMany relationships on both Term and Definition. That way you'll be able to call my_term.countries and my_definition.countries.
class Term(models.Model):
term_text = models.CharField("phrase term text", max_length=100)
country = models.ManyToManyField(Country)
class Definition(models.Model):
term = models.ForeignKey(Term)
definition_text = models.TextField()
country = models.ManyToManyField(Country)
class Country(models.Model):
# define Country model
class Meta:
verbose_name_plural = "countries"

Related

unique_together and M2M field

I have the following Model:
class CodeSynonyms(models.Model):
code = models.ForeignKey(Codes, on_delete=models.CASCADE)
websites = models.ManyToManyField(Websites)
synonym = models.Charfield(max_length=10)
The idea is that Websites use the Synonyms for specific Codes. One Website can't have few Synonyms for a Code; various Websites can share the same Synonym for specific Code. The following won't work:
class Meta:
unique together = ('code', 'websites')
" 'unique_together' refers to a ManyToManyField 'websites', but ManyToManyFields are not permitted in 'unique_together' "
Is there a way to solve this keeping the M2M relation? It would be handy to have it
you can use through in ManyToManyFieldand connect your many to many relations through custom intermediate table. then add unique_together there:
class CodeSynonyms(models.Model):
# add through field
websites = models.ManyToManyField(Websites, through='WebsiteCode')
synonym = models.Charfield(max_length=10)
class WebsiteCode(models.Model):
code_synonym = models.ForeignKey(CodeSynonyms, on_delete=models.CASCADE)
website = models.ForeignKey(Websites, on_delete=models.CASCADE)
code = models.ForeignKey(Codes, on_delete=models.CASCADE)
class Meta:
unique together = ('code', 'website')

Include Specific Foreign Keys in DRF Serializer

Here's two simple models to use as an example:
class Author(models.Model):
name = models.CharField(blank=True, max_length=50)
age = models.IntegerField(null=True, )
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author)
date = models.DateField()
Now what I'd like to do, is create a view for Book that pulls in one of the values from Author using the Django Rest Framework. Here's an example ModelSerializer:
class BookMetaSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('title','date','author__name',)
The trouble is that one can't access the fields of a foriegn key in the DRF like I gave above author__name. I haven't been able to figure out how to do this based on the documentation. All help is appreciated, thanks!
You can define author_name field with source argument to get the name of an author.
From the DRF docs on source argument:
The name of the attribute that will be used to populate the field. May
be a method that only takes a self argument, such as
URLField('get_absolute_url'), or may use dotted notation to traverse
attributes, such as EmailField(source='user.email').
Final Code:
class BookMetaSerializer(serializers.ModelSerializer):
# use dotted notation to traverse to 'name' attribute
author_name = serializers.CharField(source='author.name', read_only=True)
class Meta:
model = Book
fields = ('title','date','author_name',)

Group ManyToMany in Django admin

I have a model "Company" having many to many relationships with Country and City while country and city have one to many relationship between them.
The problem is that when loading an "enterprise" have to select the countries atienede the company and the cities they serve, but the list of cities is very long and also the cities are all mixed without distinguishing what country you are. What I'd like is to group the cities by country.
It is exactly what django-smart-selects, only this plugin does not work in many to many relationships. Someone could help me adapt this plugin to work with many to many relationship or comment me if they think of another alternative.
Thank you very much!
class Company(models.Model):
name = models.CharField(max_length=255)
countries = models.ManyToManyField(Country)
cities = models.ManyToManyField(City)
class Country(models.Model):
name = models.CharField(max_length=255)
class City(models.Model):
name = models.CharField(max_length=255)
country = models.ForeignKey(Country)
Here is a solution how you can solve this in the admin with smart_selects:
Define the through model for your manytomany relationship (company to city). In the through model you define the relationship to the city as GroupedForeignKey. Then you make an inline in the admin for your Conpany with the through model.
class Country(models.Model):
name=models.CharField(max_length=50)
class City(models.Model):
name=models.CharField(max_length=50)
country=models.ForeignKey(Country)
class CCRel(models.Model):
city= GroupedForeignKey(City, "country")
company = models.ForeignKey("Company")
class Company(models.Model):
name=models.CharField(max_length=50)
country = models.ManyToManyField(Country,through="CCRel")
And the admin.py:
class CInline(admin.TabularInline):
model = CCRel
class CAdmin(admin.ModelAdmin):
inlines=[CInline]
admin.site.register(Company,CAdmin)
It should also work with ChainedForeignKey in a similar manner.
You should remove the country field from the Company model as this is redundant.

django implementation of models

I have to implement two models in a django project --> Country and Continent.
It is possible to import all information about countries and continents from an XML file that populates the database with these two tables.
I've implemented them in this way
from django.db import models
class Continent(models.Model):
name = models.CharField(max_length=255, unique=True)
code = models.CharField(max_length=255, unique=True)
countries = ?
class Meta:
ordering = ['name']
class Country(models.Model):
name = models.CharField(max_length=255)
capital = models.CharField(max_length=255)
code = models.CharField(max_length=255, unique=True)
population = models.IntegerField(default=0)
area = models.IntegerField(default=0)
continent = models.ForeignKey(Continent)
class Meta:
ordering = ['name']
You can see a ? mark in Continent.countries because I don't understand how to implement it. The problem is: "Countries of a continent should be accessible through attribute countries of class Continent"
This means that it is possible to do this:
from MyApplication.model import Country, Continent
europe = Continent.object.get(code=u'eu')
finland = europe.countries.get(code=u'fi')
I've tried models.ForeignKey, but it doesn't work.
It says that "Nonetype object doesn't have any get method"
Can anyone help me please?
Thanks
Django does not support one to many directly, instead you can use the reverse of one-to-one relation to get a one-to-many relation.
So, go ahead with the other approach of using many to one by adding foreign key inside the country relating to continent. Now, you have a one-to-one from country to continent. Next, do a reverse query from Continent's object to get the desired relation. Take a look:
class Continent(models.Model):
...
class Country(models.Model):
...
continent = models.ForeignKey(Continent, related_name="countries")
...
europe = Continent.object.get(code=u'eu')
finland = europe.countries.get(code=u'fi')

How do I write a Django model with ManyToMany relationsship with self through a Model

I want to have a model with a ManyToMany relationship with itself, I don't know how to write this but I'l try to write some code to illustrate what I want to do.
class Person(models.Model):
name = models.CharField()
occupation = models.CharField()
friends = models.ManyToManyField('self', through = PersonFriends)
My Model that I want the friends to go through
class PersonFriends(models.Model)
???
comment = models.CharField()
In a ManyToMany field with through relationship if the other model's name was "Pet" for example I'd name my fields in that through class person and pet and make them models. ForeignKey(Person) and Pet for example
What to I name my fields in my PersonFriends model for the two person-fields now that they are the same model?
You can do something like this:
class Person(models.Model):
name = models.CharField(max_length = 255)
occupation = models.CharField(max_length = 255)
friends = models.ManyToManyField('self', through = 'PersonFriends',
symmetrical = False)
# ^^^^^^^^^^^
# This has to be false when using `through` models. Or else your
# model will not validate.
class PersonFriends(models.Model):
source = models.ForeignKey(Person, related_name = 'source')
# ^^^^^^^^^^^^
# You need different `related_name` for each when you have
# multiple foreign keys to the same table.
target = models.ForeignKey(Person, related_name = 'target')
comment = models.CharField(max_length = 255)
Everything is described in the official docs for ManyToManyField.through_fields (you can search for 'recursive relationships' phrase there to quickly find what you need):
for django 1.11 you have to specify through and (!) through_fields arguments:
class Person(models.Model):
name = models.CharField(max_length=50)
# note the additional arguments here
friends = models.ManyToManyField(
'self',
# recursive relationships to self with intermediary
# through model are always defined as non-symmetrical
symmetrical=False,
through='PersonFriend',
# this argument is required to define a custom
# through model for many to many relationship to self
# position matters: 1 - source (from), 2 - target (to)
through_fields=('person', 'friend'),
)
class PersonFriend(models.Model):
# required relationship-defining foreign keys
# (note that the order does not matter, it matters
# in 'through_fields' argument in 'friends' field of the 'Person' model)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
friend = models.ForeignKey(Person, on_delete=models.CASCADE)
# additional fields
comment = models.CharField()
Without assuming that friendships are symmetrical. Because Buzz Lightyear might be Woody's friend, but Woody isn't friends with Buzz Lightyear till near the end of the film. You can simplify both models and still have reasonable lookup names. You would of course need to make sure that you define two PersonFriends if it's a good friendship.
class Person(models.Model):
name = models.CharField()
occupation = models.CharField()
class PersonFriends(models.Model):
from_person = models.ForeignKey(Person, related_name='friends_with')
to_person = models.ForeignKey(Person, related_name='friends')
comment = models.CharField()
class Meta:
unique_together = ('from_person', 'to_person')
This has the added bonus of a comment for each direction of the friendship. i.e. Tyrion thinks Sansa is a lovely and intelligent, but lost girl. Whereas Sansa might think that Tyrion is an ugly but clever and kind-hearted kinda guy.
class PersonFriends(models.Model):
from_person = models.ForeignKey(Person, related_name='from_person')
to_person = models.ForeignKey(Person, related_name='to_person')
this is from db table structure of a ManyToMany relation to self from my Model structure. Django defines it like that..