Serializer for fetchiing data from multiple classes - python

Environment is Python and Django3
I want to make api which retrieve the data from multiple model class.
I have models like this , each CountryStat has Country.
class Country(models.Model):
code = models.CharField(max_length=3,unique=True)
name = models.CharField(max_length=50)
class CountryStat((models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE,null=True)
date = models.DateField(null=True,blank =True)
stat = models.IntegerField()
Now I want to get the latest Coutry Stat for each Country.
So I made the serializer for Country
class CountrySerializer(serializers.ModelSerializer):
latest_stat = serializers.SerializerMethodField()
class Meta:
model = Country
fields = ('id','code','latest_stat')
def get_latest_stat(self,obj):
# how can I get the latest stat from CountryStat model ????
Is this the correct idea or how can I make it??

You should define a custom latest_stat attribute on your model:
class Country(models.Model):
code = models.CharField(max_length=3,unique=True)
name = models.CharField(max_length=50)
def latest_stat(self):
return self.countrystat_set.order_by('-date').first()

Related

Trying to test a nested serilailzer, how to create required subfactories?

I am getting a failing test because (I think) I can't add a subfactory field.
I have a serializer that calls on another serializer. I am finding it difficult to replicate this in a test (specifically the factory). The issue is caused by my test: _expected_restuarant_response. It is expecting a response that includes an employee field (like the serializer does). The problem is that I can't add this subfactory field to RestaurantFactory because RestaurantFactory is located above EmployeeFactory in the factories.py file (EmployeeFactory has not yet been initialised at that point in the file). I also can't put EmployeeFactory higher than RestaurantFactory because it refers to RestaurantFactory.
Could somebody point me in the right direction? Thank you.
A simplified version of my files:
models.py:
class Restaurant(models.Model):
name = models.CharField(max_length=20)
class Employee(models.Model):
badge_id = models.CharField(max_length=20)
restaurant = models.ForeignKey(Restaurant)
serializers.py:
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = [
'badge_id']
class RestaurantSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer(many=True, read_only=True)
class Meta:
model = Restaurant
fields = [
'name',
'employee']
factories.py:
class RestaurantFactory(factory.django.DjangoModelFactory):
name = factory.Faker('company')
< ----------------------------------- do I need to add an Employee subfactory here? If so how?
class EmployeeFactory(factory.django.DjangoModelFactory):
badge_id = factory.Faker('id')
restaurant = factory.SubFactory(RestaurantFactory)
test.py:
def _expected_restuarant_response(restaurant):
return {
restaurant.name,
restaurant.employee_set.badge_id <---- the test fails here because the RestaurantFactory does not include this field
}
assert response_json == [_expected_restaurant_response(RestaurantFactory())]
In terms of the Factory creation you could probably do something like this:
class RestaurantFactory(factory.django.DjangoModelFactory):
name = factory.Faker('company')
employee = factory.SubFactory('path.to.EmployeeFactory', employee=None)
then on EmployeeFactory do this:
class EmployeeFactory(factory.django.DjangoModelFactory):
badge_id = factory.Faker('id')
restaurant = factory.RelatedFactory(RestaurantFactory, factory_related_name='employee')

Django Models Select a car model based on Car Make

Somewhat new to Django and I'm trying to create a car listing site. I've already ran into problems with the models. I can't seem figure out how I can create a model where if you select a particular make (e.g. Dodge) then you can select a model related to that make (e.g. Charger, Challenger, Viper etc.) or if you selected McLaren you could select from the 720s, 765lt, Senna, P1 etc.
models.py
class Make(models.Model):
make = models.CharField('Make', max_length=150)
class Meta:
ordering = ['make']
unique_together = ["make"]
verbose_name_plural = "Manufacturers"
def __str__(self):
return self.make
class CarModel(models.Model):
year = models.IntegerField(default=datetime.datetime.today().year)
make = models.ForeignKey(Make, on_delete=models.CASCADE)
model = models.CharField('Model', max_length=150)
trim = models.CharField('Trim', max_length=150, help_text='Trim level')
class Meta:
ordering = ['make', 'model', 'trim', 'year']
unique_together = ("year", "make", "model", "trim")
verbose_name_plural = "Models"
def __str__(self):
return f' {self.year} {self.make} {self.model} {self.trim}'
class CarListing(models.Model):
content = models.FileField("Media")
make = models.ForeignKey(Make, on_delete=models.CASCADE)
make_model = models.ForeignKey(CarModel, on_delete=models.CASCADE)
class Meta:
ordering = ['make_model']
verbose_name_plural = "Car Listings"
def __str__(self):
return f' {self.make_model.year} {self.make_model.make}
{self.make_model.model}
{self.make_model.trim} '
Use related_name for backwards compatibility.
class CarModel(models.Model):
year = models.IntegerField(default=datetime.datetime.today().year)
make = models.ForeignKey(Make, on_delete=models.CASCADE, related_name="models") # Note the related name here
model = models.CharField('Model', max_length=150)
trim = models.CharField('Trim', max_length=150, help_text='Trim level')
Then when you have a related name, you can easily access it by calling models on an instance
make = Make.objects.get(make="Dodge")
print(make.models) # Viper, Charger, Challenger, etc.
Note: make = Make.objects.get(make="Dodge") this will fire you an error if there are multiple records with the same query.
So you have to do something like this:
make = Make.objects.filter(make="Dodge") # return list of records`

django model reference to own attribute

When i create a Django model i want to set the primary_key/ID to a combination of 2 attributes of this Model.
Example model:
class Example(models.Model):
name = models.CharField(max_length=100)
date = models.DateTimeField(default=now)
id = models.CharField(max_length=100, default="{}-{}".format(name, date) primary_key=True)
But he is saving the Model and not the values:
field=models.CharField(default='<django.db.models.fields.related.ForeignKey>-<django.db.models.fields.DateTimeField>', max_length=100, primary_key=True, serialize=False),
I know that name and date are a model in this context, but "self." is not working and i can't find a Django function to get the actual values instead.
It should work like this:
Input:
testmodel = Example(name="foo", date=datetime.now())
testmodel.save()
testmodel-id should look something like this "foo-2020-12-11..."
I don't think you can do that. Because these values are initialized at the making of an object. What you can do is to make your own class method to initialize these values.
class Example(models.Model):
name = models.CharField(max_length=100)
date = models.DateTimeField(default=now)
id = models.CharField(max_length=100, primary_key=True)
# In User class declaration
#classmethod
def create(cls,name, date):
return cls(name=name, date=date, id="{}-{}".format(name,date))
And Use it like this outside the class
p = Example.create("Fred", "11-12-2020")

Not sure I understand dependancy between 2 django models

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

Django import-export.admin customize:for xlsx sheets, and change the diff strategy

I have a knotty problem. I used django-import-export
to import xlsx data. I have integrated it to Django admin by ImportExportModelAdmin. below is admin.py:
#admin.register(assets)
class data_import(ImportExportModelAdmin):
pass
But when I import data several times, I found it just save the newest data(the last) to model, I want save all data every time I import, and just use some columns to decide if the data is duplicated.How can I solve this?
model.py:
class station(models.Model):
station_name = models.CharField(max_length=100, verbose_name='Astation')
class assets(model.Model):
name = models.CharField(max_length = 200, verbose_name = 'Aname')
sn = models.CharField(max_length=200, verbose_name='Asn', default=None)
ip_address = models.GenericIPAddressField(u'IP', blank=True, null=True)
station = models.ForeignKey(station)
You can create a resource class and override get_instance method and return False always
from import_export import resources, fields
from import_export.widgets import ForeignKeyWidget
class DataResource(resources.ModelResource):
# UPDATE
# If model has ForeignKey
station = fields.Field(widget=ForeignKeyWidget(station, 'id'))
def get_instance(self, instance_loader, row):
# Returning False prevents us from looking in the
# database for rows that already exist
return False
class Meta:
model = assets # class name should be camelcase
fields = '__all__' # If all column of table present in xlsx otherwise mention fields name.
#admin.register(assets)
class data_import(ImportExportModelAdmin):
resource_class = DataResource

Categories