I'm new to Django
I'm currently using django 3.2.6. I want make multiple instances of route_stop model and store in SchoolRouteStop.route_graph model.I don't want use ForeignKey because i want to make somthing like like nested dict.
from django.db import models
class geo_fence(models.Model):
radius = models.FloatField()
class geo_location(models.Model):
latitude = models.FloatField()
longitude = models.FloatField()
class address(models.Model):
entity = models.fields.CharField(max_length=100)
apt_plot = models.fields.CharField(max_length=100)
street = models.fields.CharField(max_length=100)
city = models.fields.CharField(max_length=100)
state = models.fields.CharField(max_length=2) #state name in short code
zip_code = models.fields.IntegerField()
class route_stop(models.Model): # this for multiple bus stops
route_stop_id = models.fields.IntegerField()
school_id = models.fields.CharField(max_length=100)
route_number = models.fields.CharField(max_length=100)
school_route_stop_uuid = models.fields.CharField(max_length=100, primary_key=True)
registered_arrival_time = models.TimeField()
time_from_src = models.FloatField()
is_school = models.BooleanField(default=False)
geo_fence = models.ForeignKey(geo_fence, on_delete =models.CASCADE)
geo_location = models.ForeignKey(geo_location, on_delete = models.CASCADE)
address = models.ForeignKey(address, on_delete = models.CASCADE)
class SchoolRouteStop(models.Model):
school_id = models.CharField(max_length=100)
school_route_number = models.IntegerField()
route_type = models.CharField(max_length=2)
route_id = str(school_id)+'_'+str(school_route_number)+str(route_type)
route_graph= models.ForeignKey(route_stop,related_name='School', on_delete = models.CASCADE)
# Create your models here.
You have to use a ForeignKey here because you will lose all the Django ORM features and performances if you try to hack this.
Trying to use a JSONField or something else instead would also mean losing integrity constraints you would need to implement yourself, which you really want to avoid.
The way Django works is you implement your models to be stored efficiently in the database, then you use views & serializers to manipulate them.
Your models need to be refined, I really have a hard time understanding their real purpose because there are id fields everywhere (that should also probably be ForeignkeyField), and everything seems a little confusing.
For example, why is school_route_stop_uuid a CharField when UUIDField does exist?
Why is route_id not a property?
Also, make sure to follow the naming conventions in Python, it will make you code way cleaner. According to PEP 8 (https://www.python.org/dev/peps/pep-0008/#class-names):
Class names should normally use the CapWords convention.
Related
For example, I have a lot of interrelated tables in my project
class A(models.Model):
name = models.models.CharField(max_length=16)
class B(models.Model):
name = models.models.CharField(max_length=16)
a = models.ForeignKey(A, on_delete=models.CASCADE)
class C(models.Model):
name = models.models.CharField(max_length=16)
b = models.ForeignKey(B, on_delete=models.CASCADE)
and so on.
I need to test model C and have no interest in A and B models. Is there any chance to mock model B that can be used when creating model C objects?
I mean I'd like to create few objects without building a massive base just to test one tiny model.
You can use bakery
from model_bakery import baker
AmodelInstance = baker.make(A)
If it is only for some tests and you only need a few instances you could do something like this:
model_a_instance = A(name='somename')
model_b_instance = B(name='somename2', a=model_a_instance)
model_c_instance = C(name='somename3', b=model_b_instance)
Nonetheless, if you need to save model_c in the DB make sure to save model_a and model_b also.
If you are going to need these models more extensively I would recommend creating a factory class to populate your models.
Hopefully this helped.
After couple of days of research I don't have an answer to my question, but I think I found a tool that takes care of 'preparing the base' before actual testing or greatly simplifies it.
I have about 1000 lines of test code in my project and I decided to switch to pytest and rewrite tests almost from scratch, so, I'm actually doing what I hoped to avoid, but it's acceptable for me in this case.
Instead of creating queryset objects via django ORM I utilize Factory Boy to define factories that resolve database relations in the way I want.
For the example case I would implement something like that:
import factory
class AFactory(factory.django.DjangoModelFactory):
class Meta:
model = A
class BFactory(factory.django.DjangoModelFactory):
class Meta:
model = B
a = factory.SubFactory(AFactory)
class CFactory(factory.django.DjangoModelFactory):
class Meta:
model = C
b = factory.SubFactory(BFactory)
So, to test C model you're just creating C model object via CFactory.create(), and all 'chain' stuff is handled using SubFactories.
However, example models have no any constraints, unlike real database tables. Here's an example for more descriptive answer:
class Country(models.Model):
name = models.CharField(choices=(('BY', 'Belarus'), ('UA', 'Ukraine')),
max_length=64, unique=True)
class Employee(models.Model):
name = models.CharField(max_length=64)
email = models.EmailField(max_length=100, unique=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class Supervisor(models.Model):
name = models.CharField(max_length=64)
email = models.EmailField(max_length=100, unique=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
If I would use same approach as with A B C example and executed something like SupervisorFactory.create() at least 2 times I violated Country.name and Employee.email constraints. 2 SupervisorFactory calls would try to create 4 countries, but it's possibly to create only 3 - 'BY', 'UA', and empty string that is factory boy's default. Thus, you should specify the rules factories generate data by:
class CountryFactory(factory.django.DjangoModelFactory):
class Meta:
model = Country
django_get_or_create = ('name',)
name = factory.Iterator('BY', 'UA')
class EmployeeFactory(factory.django.DjangoModelFactory):
class Meta:
model = Employee
email = factory.Sequence(lambda nums: 'employee.%04d#employee.io' % nums)
country = factory.SubFactory(CountryFactory)
class Supervisor(factory.django.DjangoModelFactory):
class Meta:
model = Supervisor
email = factory.Sequence(lambda nums: 'supervisor.%04d#supervisor.io' % nums)
country = factory.SubFactory(CountryFactory)
employee = factory.SubFactory(EmployeeFactory)
Hope this will save your time.
I am struggling to understand django models relationship.
I have this arborescence:
A train have cars, and those cars are divided into parts. Then those parts all contains different references.
Like, for exemple, all the trains have the 6 cars, and the cars 6 parts. Each part have x reference to be associated.
I would like to use all of them in a template later on, where the user can select the train, the car and the part he worked on, then generate a table from his selections with only the references associated to the parts he selected.
It should update the train and the car (I'm trying to update a stock of elements for a company)
I dont really understand which model field give to each of them. After checking the doc, Ive done something like this but i am not convinced:
class Train(Car):
train = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Car(Part):
car = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Part(Reference):
part = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Reference(models.Model):
reference = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
def __str__(self):
return self.reference
Can someone please help me understand this so I can do well ? Thanks!!
1-)if you add abstract = True in your Model Meta class, your class doesn't created on database as a table. If you store data for any class, you mustn't define abstract = True.
2-)For relations, you can use models.ForeignKey . If you add a class into brackets of another class, it names: inheritance.(You can think like parent-child relation). In database management, we can use foreignkey for one-to-many relationship.
3-)In Django ORM, id field automatically generated. So you don't need to define id field.
If I understand correctly, also you want to store parts of user's selected.
So, your model can be like that:
class Train(models.Model):
name = models.CharField(max_length=200) # I think you want to save name of train
class Car(models.Model):
train = models.ForeignKey(Train,on_delete=models.Cascade)
name = models.CharField(max_length=200)
class Part(models.Model):
car = models.ForeignKey(Car,on_delete=models.Cascade)
name = models.CharField(max_length=200)
class Reference(models.Model):
part = models.ForeignKey(Part,on_delete=models.Cascade)
name = models.CharField(max_length=200)
def __str__(self):
return self.reference
#addtional table for storing user's references
class UserReference(models.Model):
user = models.ForeignKey(User,on_delete=models.Cascade)
reference = models.ForeignKey(Reference,on_delete=models.Cascade)
name = models.CharField(max_length=200)
With this definitions, you can store user's definition on UserReference table. And with Django Orm, you can access train object from UserReferenceObject.
#user_reference: UserReference object like that result of UserReference.objects.first()
user_reference.reference.part.car.train.name
What is a better way of realizing rate field in model. Now I have this one:
class Story(models.Model):
...
rate = models.(help here)
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
Or there is another way of doing this?
As #Liudvikas Bajarunas said, it's enough to define story as a foreign key on the Rating model. You can access the story ratings using rating_set:
story_ratings = story.rating_set.all()
See the documentation on following relationships backwards for more info.
You can combine that approach with aggregation to get the average rating of a story:
class Story(models.Model):
...
#property
def average_rating(self):
return self.rating_set.all().aggregate(Avg('rate'))['rate__avg']
There are some improvements that you can make:
It is better to refer to the user model with the AUTH_USER_MODEL setting [Django-doc] to refer to the user model, since you can later change your mind about it;
You probably want to make user and story unique together, such that a user can not make two ratings for the same story;
some databases, like PostgreSQL allow us to enforce range constraints at the database level, and thus make it more safe.
we thus can rewrite this to:
from django.conf import settings
from django.db import models
from django.db.models import CheckConstraint, Q, UniqueConstraint
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Meta:
constraints = [
CheckConstraint(check=Q(rate__range=(0, 10)), name='valid_rate'),
UniqueConstraint(fields=['user', 'story'], name='rating_once')
]
You should either go with a through field like this:
class Story(models.Model):
rates = models.ManyToManyField(User, through=Rating)
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
or you can do it your way with a separate model which in this case your either should remove the rate field from Story model or remove the story field from Rating model:
class Story(models.Model):
...
# rate = models.(help here) No need anymore
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
and your queryset will be something like this:
story.rating_set.all()
Which will include all the ratings for the selected story instance.
I'm working on a web for translators. I'm stucked on designing a structure of the data. So there is a model Translator, Language and Level. The price depends on Language and Level (Standard level multiplies the price 1x, Professional 1.5x etc.)
Each Translator can translate multiple languages with different levels (skills).
I can't figure out how to design models for this purpose. My idea is to store for each Translator some field of tuples (Language,Level) so the model Translator would be:
class TranslatorProfile(models.Model):
user = models.OneToOneField(User, related_name='userprofile')
date_of_birth = models.DateField(null=True,blank=True)
telephone = models.CharField(max_length=40,null=True,blank=True)
IBAN = models.CharField(max_length=40,null=True,blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
# HERE IS THE PROBLEM
languages = models.FieldOfModelTuples(Language,Level)
class Level(models.Model):
LEVEL_NAMES = (
('standard', 'Standard'),
('professional', 'Professional'),
#etc.
)
name = models.CharField(max_length=40, choices=LEVEL_NAMES)
price_multiplier = models.FloatField()
class Language(models.Model):
shortcut = models.CharField(max_length=40)
name = models.CharField(max_length=40)
def __str__(self):
return self.name
I would appreciate any advice how to solve this problem (.FieldOfModelTuples does not exists of course). Maybe there is a simpler way to do this.
I think that Level should be a field on a through-model for a many-to-many relationship between TranslatorProfile and Language:
class TranslatorLanguage(models.Model):
translator = models.ForeignKey('app_name.TranslatorProfile')
language = models.ForeignKey('app_name.Language')
level = models.ForeignKey('app_name.Level')
class Meta:
unique_together = (('translator', 'language'),)
this allows you to query all necessary properties for each Translator-Language pair. Access to a translator's languages can then be simplified via:
# HERE IS THE PROBLEM
languages = models.ManyToManyField(Language, through='TranslatorLanguage')
Hello to the stackoverflow team,
I have the following two django tables:
class StraightredFixture(models.Model):
fixtureid = models.IntegerField(primary_key=True)
soccerseason = models.IntegerField(db_column='soccerSeason') # Field name made lowercase.
hometeamid = models.IntegerField()
awayteamid = models.IntegerField()
fixturedate = models.DateTimeField()
fixturestatus = models.CharField(max_length=24)
fixturematchday = models.IntegerField()
hometeamscore = models.IntegerField()
awayteamscore = models.IntegerField()
class Meta:
managed = False
db_table = 'straightred_fixture'
class StraightredTeam(models.Model):
teamid = models.IntegerField(primary_key=True)
teamname = models.CharField(max_length=36)
teamcode = models.CharField(max_length=5)
teamshortname = models.CharField(max_length=24)
class Meta:
managed = False
db_table = 'straightred_team'
In the views.py I know I can put the following and it works perfectly:
def test(request):
fixture = StraightredFixture.objects.get(fixtureid=136697)
return render(request,'straightred/test.html',{'name':fixture.hometeamid})
As I mentioned above, this all works well but I am looking to return the teamname of the hometeamid which can be found in the StraightredTeam model.
After some looking around I have been nudged in the direction of "select_related" but I am unclear on how to implement it in my existing tables and also if it is the most efficient way for this type of query. It feels right.
Please note this code was created using "python manage.py inspectdb".
Any advice at this stage would be greatly appreciated. Many thanks, Alan.
See model relationships.
Django provides special model fields to manage table relationships.
The one suiting your needs is ForeignKey.
Instead of declaring:
hometeamid = models.IntegerField()
awayteamid = models.IntegerField()
which I guess is the result of python manage.py inspectdb, you would declare:
home_team = models.ForeignKey('<app_name>. StraightredTeam', db_column='hometeamid', related_name='home_fixtures')
away_team = models.ForeignKey('<app_name>. StraightredTeam', db_column='awayteamid', related_name='away_fixtures')
By doing this will, you tell the Django ORM to handle the relationship under the hood, which will allow you to do such things as:
fixture = StraightredFixture.objects.get(fixtureid=some_fixture_id)
fixture.home_team # Returns the associated StraightredTeam instance.
team = StraightredTeam.objects.get(team_id=some_team_id)
team.home_fixtures.all() # Return all at home fixtures for that team.
I am not sure if this makes sense for Managed=False, but I suppose the sane way of doing it in Django would be with
home_team = models.ForeignKey('StraightRedFixture', db_column='fixtureid'))
And then just using fixture.home_team instead of doing queries by hand.