models in django. is many to many the best option? - django

I am trying to make my first website with django. Basically I'm making a website to check the bus schedule in my rural area. I think that the best thing is to make two models, one where all the bus stations are defined and the other where the route is established, for each route two stations are needed (origin and destination). I was wondering what was the best way to relate the two models.
class BusStations(models.Model):
bus_stations = models.CharField(max_length=80)
bus_stations_identifier = models.IntegerField()
def __str__(self):
return self.bus_stations
class Routes(models.Model):
origin_station = models.ManyToManyField(
BusStations, related_name='origin_station')
destination_station = models.ManyToManyField(
BusStations, related_name='destination_station')
data = models.JSONField()
slug = models.SlugField(unique=True, null=True)
def __str__(self):
return f'{self.origin_station} - {self.estacion_destino}'
For now I was doing it with ManytoMany relationships, but this is giving me problems. For example, I am not able to return the origin and destination stations as str in the route model. I would also like it to be the slug.

The origin_station and destionation_station likely each point to a single station, so then you use a ForeignKey [Django-doc], not a ManyToManyField:
class BusStation(models.Model):
bus_station = models.CharField(max_length=80)
bus_station_identifier = models.IntegerField()
def __str__(self):
return self.bus_station
class Route(models.Model):
origin_station = models.ForeignKey(
BusStation, related_name='starting_routes'
)
destination_station = models.ForeignKey(
BusStation, related_name='ending_routes'
)
data = models.JSONField()
slug = models.SlugField(unique=True, null=True)
def __str__(self):
return f'{self.origin_station} - {self.destionation_station}'

Related

How to relationship such a connection in django?

I need to implement a "end-to-end" connection between products.
like this:
I automatically put down two-way links between two products. But when I link product A to product B and product B to product C, there is no connection between A and C. It is necessary that they communicate themselves when putting down the two previous links.
Models.py
from django.db import models
class Part(models.Model):
brand = models.CharField('Производитель', max_length=100, blank=True)
number = models.CharField('Артикул', max_length=100, unique=True)
name = models.CharField('Название', max_length=100, blank=True)
description = models.TextField('Комментарий', blank=True, max_length=5000)
analog = models.ManyToManyField('self',blank=True, related_name='AnalogParts')
images = models.FileField('Главное изображение', upload_to = 'parts/', blank=True)
images0 = models.FileField('Дополнительное фото', upload_to = 'parts/', blank=True)
images1 = models.FileField('Дополнительное фото', upload_to = 'parts/', blank=True)
images2 = models.FileField('Дополнительное фото', upload_to = 'parts/', blank=True)
def __str__(self):
return str(self.number)
return self.name
class Meta:
verbose_name = 'Запчасть'
verbose_name_plural = 'Запчасти'
Your diagram looks like Parts are connected linear. The easiest way to accomplish that is to add OneToOneFields to the model it self like so:
next = models.OneToOneField('self', related_name='previous', null=True)
Then you can do something like
part = Part.object.get(name='wheel')
while part.next:
part = part.next
# At this point Part is the last part in the row
print(part)
This is the most easy way. Depending whether you have linear connections between parts only you have to adjust your fields. There is no solution to all of the graph problems unless you realize some graph structure/database which will solve common problems (I think GraphQL can do such stuff, but iam not sure). Also keep in mind that this will most probably execute one SQL query per loop iteration.

how to filter data in different models in django?

my models
class Player(TimeStampedModel):
name = models.CharField(max_length=200)
email = models.CharField(max_length=200)
email_verified = models.BooleanField(default=False, blank=True)
phone = models.CharField(max_length=200)
phone_verified = models.BooleanField(default=False, blank=True)
company_id = models.ImageField(upload_to=get_file_path_id_card, null=True,
max_length=255)
company_id_verified = models.BooleanField(default=False, blank=True)
team = models.ForeignKey(Team, related_name='player', on_delete=models.DO_NOTHING)
def __str__(self):
return self.name
this is my model , how to filter data in multiple model?
You can use a Queryset to filter by modal object's field.
You can use this to also filter relationships on models.
In your example, you can do a filter of all the Player entries that have a Character that have Weapon with strength > 10
Player.objects.filter(character__weapon__strength__gt=10)
You can also separate them out into 3 variables for readability purposes.
player_q = Player.objects.filter(character__isnull=False)
ch_q = player_q.filter(weapon__isnull=False)
wpn_dmg = ch_q.filter(strength__gt=10)
Please note that filters are lazy and thus don't return actual model instances untill they're evaluated. I think in this case gt returns an instance.
This documentation goes over all the fieldset lookups you can do with QuerySet object methods filter(), get(), and exclude()

Django tables connection

I have 3 django tables connected like this:
Is there anyway to make a query for table Table that will get id_equip from table equip?
models.py
class Vendor(models.Model):
vendor_name = models.CharField(max_length=50)
def __str__(self):
return self.vendor_name
class Equipment(models.Model):
equipment_name = models.CharField(max_length=50)
id_vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
def __str__(self):
return self.equipment_name
class Table(models.Model):
table_name = models.CharField(max_length=100)
id_vend = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
id_equip = models.ManyToManyField(Equipment)
This part of the django docs is relevant and helpful, I definitely recommend your review at least that section and ideally the whole page.
Your models are already denormalized as evidenced by Table.id_equip which relates to Equipment so you could do:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(table.id_equip.all().values_list('id', flat=True))
If you wanted to go through the vendor I'd suggest:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(Equipment.objects.filter(vendor_set__table_set=table).values_list('id', flat=True))
I would recommend that you don't name your relationship fields with id_. With an ORM, these fields should represent the instances of the Model they are mapping to. For example:
class Table(models.Model):
name = models.CharField(max_length=100)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
equipment = models.ManyToManyField(Equipment)
If you're trying to create the model on top of an existing table, you can make use of the db_column parameter when defining the field.
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, db_column="id_vend")

Django: need help in designing relationships between models

I have an app which allows to associate to each client multiple boards, boards where I can upload files relevant for the client to make decisions about how the website page in question will look.
So the relationships I need to model are:
one client, multiple boards;
one board, one client;
one board, multiple files;
Let's concentrate on the first two
models.py
class Board(models.Model):
title = models.CharField(max_length=120, verbose_name="Titolo")
description = models.TextField()
files = models.FileField( null=True, blank=True, upload_to = 'clients_download_area', verbose_name = 'Client Reserved File')
date = models.DateTimeField(auto_now_add=True, verbose_name = 'Data di pubblicazione')
def __str__(self):
return str(self.title)
class Client(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=120)
boards = models.ManyToManyField(Board, blank=True)
def __str__(self):
return str(self.name)
Ok, relationship #1 is done. But what if I need to know which client is associated to a board (relationship #2)?
If I set a new field to Board Class
class Board(models.Model):
[...]
client = models.ForeignKey(Client, blank = True)
of course, when I makemigrations Django complains because it does not know what Client is, since I define it in the next model.
How can I design this DB?
Thank you in advance for any help you could provide
The problem here is that you reference to an identifer (here Client), before it is constructed (since Board is defined before the Client class).
Django has some support for this: you can pass strings that contain the name of the model. In the same app, you can just use ClassName, for another app, you can use other_app.ClassName, like the documentation says:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model
object itself:
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
So here you can write it like:
class Board(models.Model):
title = models.CharField(max_length=120, verbose_name="Titolo")
description = models.TextField()
files = models.FileField( null=True, blank=True, upload_to = 'clients_download_area', verbose_name = 'Client Reserved File')
date = models.DateTimeField(auto_now_add=True, verbose_name = 'Data di pubblicazione')
client = models.ForeignKey(
'Client',
related_name='my_boards'
on_delete=models.CASCADE
)
def __str__(self):
return str(self.title)
class Client(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=120)
boards = models.ManyToManyField(Board, blank=True)
def __str__(self):
return str(self.name)
Note however that you already defined a ManyToManyField relation from Client to Board. Although it is possible it is not very common that two such relations exists simultaneously.
If you define a ForeignKey relationship from Board to Client, then Django automatically creates a reverse relationship (with the related_name), such that some_client.my_boards, is a manager of all the related Boards.
I think you can pass model class name instead of the class itself:
class Board(models.Model):
[...]
client_id = models.ForeignKey('Client', blank=True)

reverse look up based on foreign key queryset data

Ok, I trust that the title may be confusing. As we go along I may update the question title in order to better reflect what it is referring to.
However. I have 3 models currently, Zone, Boss and Difficulty. The models are linked via ForeignKey relationships like so:
class Difficulty(models.Model):
'''Define the difficulties available in game'''
difficulty = models.CharField(max_length=255, null=True)
def __unicode__(self):
return self.difficulty
class Meta:
verbose_name = "Difficulty Setting"
verbose_name_plural = "Difficulties"
class Zone(models.Model):
'''Stores the Zone information, referred to in-game as a Raid Instance'''
name = models.CharField(max_length=255, null=True)
zone_id = models.IntegerField(null=True)
def __unicode__(self):
return self.name
class Boss(models.Model):
'''Stores the information for each boss encounter within each zone'''
name = models.CharField(max_length=255, null=True)
boss_id = models.IntegerField(null=True, blank=True)
zone = models.ForeignKey(Zone, null=True)
difficulty = models.ForeignKey(Difficulty, null=True)
guild_defeated = models.BooleanField(default=False)
appearance = models.IntegerField(null=True, blank=True)
def __unicode__(self):
return u'%s [%s]' % (self.name, self.difficulty)
class Meta:
ordering = ['difficulty', 'appearance']
verbose_name = "Boss"
verbose_name_plural = "Bosses"
What I am trying to achieve, Is filter each Zone, based on Difficulty.
For example
If Zone 1 has a Boss with 3 separate difficulties [a, b, c] I want to be able to get the data so that I can separately show in the template Zone 1 (Difficulty A), Zone 1 (Difficulty B) and Zone 1 (Difficulty C) and list each of the zones' bosses accordingly.
This is a bit easier if you add a ManyToManyField to Zone (or Difficulty):
class Zone(models.Model):
difficulties = models.ManyToManyField(Difficulty, through=Boss, related_name='zones')
Then, you can query for all the difficulties related to a single zone:
for difficulty in zone.difficulties.all():
bosses = difficulty.boss_set.filter(zone=zone)
To help with performance, use prefetch_related('difficulties'). In Django 1.7 you can use the new Prefetch object to also prefetch the bosses:
# I think that's how the new `Prefetch` works, I haven't actually used it yet.
zone = Zone.objects.prefetch_related(
Prefetch('difficulties'),
Prefetch('difficulties__bosses', queryset=Boss.objects.filter(zone_id=zone_id),
).get(...)