How to use custom fields for complex django models? - django

I want to define a model where a field can be one of the other defined models.
I have three models like Plane, Train and Bus. Each model has its own fields.
e.g.
class Train(models.Model):
id = models.AutoField(primary_key=True)
train_name = models.CharField(max_length=200)
date_of_journey= models.DateField()
from_station = models.CharField(max_length=4)
to_station = models.CharField(max_length=4)
class_selection = models.CharField(max_length=6, choices=class_choices)
and
class Plane(models.Model):
id = models.AutoField(primary_key=True)
date_of_journey= models.DateField()
from_airport = models.CharField(max_length=4)
to_airport = models.CharField(max_length=4)
plane_model = models.CharField(max_length=10)
class Bus(models.Model):
id = models.AutoField(primary_key=True)
date_of_journey= models.DateField()
from_city = models.CharField(max_length=100)
to_city = models.CharField(max_length=100)
I want to make a model named Trip which will have following structure:
class Trip(models.Model):
id = models.AutoField(primary_key=True)
trip_name = models.CharField(max_length=250)
reason = models.CharField(max_length=30, null=True, blank=True)
individual_journey = JourneyType(oneToManyField)
A trip can have multiple individual journeys and each journey should be either a Bus journey, a Train journey or a plane journey.

from django.core.exceptions import ValidationError
class JourneyType(models.Model):
bus = models.ForeignKey('Bus', blank=True, null=True)
train = models.ForeignKey('Train', blank=True, null=True)
plain = models.ForeignKey('Plain', blank=True, null=True)
def clean(self):
if not (self.bus or self.train or self.plain) or \
(self.bus and self.train) or (self.bus and self.plain) or \
(self.train and self.plain):
raise ValidationError('You should specify (only) one journey type')
def __unicode__(self):
if self.bus:
return 'Bus id={0}'.format(self.bus)
elif self.train:
return 'Train id={0}'.format(self.train)
else:
return 'Plain id={0}'.format(self.plain)
class Trip(models.Model):
# ...
individual_journey = models.ForeignKey('JourneyType')

Related

DRF using prefetch_related

I have two classes Vessels and Components, each vessel has several components.
I just want to fetch all vessels and all their related components in one query, I thought prefretch_related does that trick but in DRF in the api i am only receiving the vessels without their related components
models.py
class Vessel(models.Model):
name = models.CharField(max_length=255, null=True, blank=True)
imo = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
return self.name
class Component(models.Model):
vessel = models.ForeignKey(
Vessel, blank=True, null=True, on_delete=models.CASCADE, related_name='vessel_components')
name = models.CharField(max_length=200, blank=True, null=True)
manufacturer = models.CharField(max_length=200, blank=True, null=True)
model = models.CharField(max_length=200, blank=True, null=True)
type = models.CharField(max_length=200, blank=True, null=True)
remarks = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
serializers.py
class VesselSerializer(serializers.ModelSerializer):
class Meta:
model = Vessel
fields = '__all__'
class ComponentSerializer(serializers.ModelSerializer):
class Meta:
model = Component
fields = '__all__'
the view :
#api_view(['GET'])
def getVessels(request):
vessels = Vessel.objects.all().prefetch_related('vessel_components')
vSerializer = VesselSerializer(vessels, many=True)
return Response(vSerializer.data)
the result i am getting :
I thought prefretch_related does that trick but in DRF.
This will fetch the Components for the Vessels, but since your serializers do not serialize these components, these will not end up in the result.
You should define the ComponentSerializer as subserializer for VesselSerializer, so:
class ComponentSerializer(serializers.ModelSerializer):
class Meta:
model = Component
fields = '__all__'
class VesselSerializer(serializers.ModelSerializer):
vessel_components = ComponentSerializer(many=True) # 🖘 subserializer
class Meta:
model = Vessel
fields = '__all__'

Related fields on model?

There is a model ElectoralTable
class ElectoralTable(models.Model):
name = models.CharField(max_length=250)
country_owner = models.ForeignKey(Country, on_delete=models.CASCADE)
city_owner = models.ForeignKey(City, on_delete=models.CASCADE)
address = models.CharField(max_length=400)
latitude = models.CharField(max_length=250, blank=True)
longitude = models.CharField(max_length=250, blank=True)
class Country(models.Model):
name = models.CharField(max_length=250, unique=True, blank=False)
def __str__(self):
return self.name
class Meta:
ordering = ('name',)
class City(models.Model):
name = models.CharField(max_length=400, blank=True)
country_owner = models.ForeignKey(Country, on_delete=models.CASCADE, related_name='country')
def __str__(self):
return self.name
class Meta:
ordering = ('country_owner', 'name', )
How can I to select a city related to a country. Rigth now I receive every city on Model City but I want only to receive the cities related wiht country owner
Well I found one solution to prevent save a city who doesn't belong to country it was to overwrite the clean method
def clean(self):
city = City.objects.filter(country_owner__name=self.city_owner)
city_names = []
for item in city:
city_names.append(item.name)
if not str(self.city_owner) in city_names:
raise ValidationError(_('The city doesn't belong to the country'))

Django Model design for a basic inventory application

I am new to Django (and databases for that matter) and trying to create a simple inventory application to help learn. I've been through the tutorials and am going through some books, but I am stuck at what i think is simple, just not sure where to look or how to ask.
With an inventory application, you have your equipment which then has a manufacturer, which the equipment has a model number that only that manufacturer has. Lets say Dell Optiplex 3040. I am also using the admin console right now as well. So i would like to be able to relate equipment to a manufacturer and then also relate the equipment to the model number. It almost seems as I am needing to use the many to many field and the through field to accomplish what I am trying to do but I dont think that is the right way to do it (shown in the link below). https://docs.djangoproject.com/en/1.9/topics/db/models/#many-to-many-relationships
Below is the code I have so far. Thank you.
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
equipmentModel = models.CharField(max_length=50)
def __str__(self):
return self.equipmentModel
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
***Edit to add the updated code and the admin.py code in response question I had to answer.
#admin.py
from django.contrib import admin
# Register your models here.
from .models import Device,Department,Manufacturer,Employees, Job_Positions, EquipmentModel
class DeviceModelAdmin(admin.ModelAdmin):
list_display = ["ip", "department","model","serial_number","date_updated"]
list_filter = ["department","model","ip"]
search_fields = ["ip"]
class Meta:
model = Device
class EmployeesModelAdmin(admin.ModelAdmin):
list_display = ["employee_name_first", "employee_name_last", "employee_username", "phone"]
list_filter = ["department"]
class Meta:
model = Employees
admin.site.register(Device, DeviceModelAdmin)
admin.site.register(Department)
admin.site.register(Manufacturer)
admin.site.register(EquipmentModel)
admin.site.register(Employees, EmployeesModelAdmin)
admin.site.register(Job_Positions)
updated models.py
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
model_number = models.CharField(max_length=50)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
def __str__(self):
return self.model_number
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE,null=True)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
A many-to-many relationship is not what you want here, because any piece of equipment (I assume) can only have one manufacturer.
You do need an intermediate model which stores the model information, and you already have one in your EquipmentModel. I would suggest modifying it as follows:
class EquipmentModel(models.Model):
# This stores information about a particular model of device
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
model_number = models.CharField(max_length=50)
And then instead of having a foreign key to the manufacturer in Device, replace it with a foreign key to the equipment model:
class Device(models.Model):
# ...
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE)

Django filter intermediary table & social media

So i'm practicing django with a social media website(just for practice). I'm trying to do a filter in my view to get all of the "Beats" from users i'm friends with. Im using an intermediary table for "relationships". I'm currently getting my Beat Stream by using:
my_stream = Beat.objects.filter(artist=user)
But i'm trying to get only the beats of the people i'm "related_to" in the relationships model.
MODELS:
class Beat(models.Model):
created_at = models.DateTimeField( default=datetime.now)
title = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
likes = models.IntegerField(default=0)
artist = models.ForeignKey(User, null=True, blank=True)
beat_cover = models.ImageField(null=True, blank=True);
admin_name = models.CharField(max_length=255, blank=True, null=True)
class Meta:
ordering = ['-created_at']
def __unicode__(self):
return unicode(self.admin_name)
class UserProfile(models.Model):
user = models.OneToOneField(User)
admin_name = models.CharField(default="beat",max_length=255,blank=True, null=True)
def __unicode__(self):
return unicode(self.admin_name)
class Relationship(models.Model):
from_user = models.ForeignKey(User, related_name="relationships")
to_user = models.ForeignKey(User, related_name="related_to")
class Meta:
index_together = ['from_user','to_user']
You should do:
related_users = Relationship.objects.filter(from_user=user) \
.values_list('to_user', flat=True).distinct()
my_stream = Beat.objects.filter(artist__in=related_users)

Tricky issue passing data from form to form in django

I am a django newbie and have one more big struggle for longer time... :/
User can choose a 'main language' which is set as ForeignKey. User can choose 'further languages' as ManyToMany (Checkbox). Assuming, user selects english as 'main' language, so english has to be filterd out from the 'further languages'... have been searching so much and have no idea how to do it. Is this even possible without JavaScript?
Of course, I could set the 'queryset' in the second form but it would filter the objects after the submit... The similar problem is, when a selected country has to be connected to the proper zipcodes...
I am very thankful for any hints.
Best regards.
class Country(models.Model):
enter code here
country = models.CharField(max_length=40)
active = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'Länder'
def __str__(self):
return self.country
class ZipCode(models.Model):
zipcode = models.CharField(max_length=5)
city = models.CharField(max_length=255)
active = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'Postleitzahlen'
def __str__(self):
return '{0} {1}'.format(self.zipcode, self.city)
class MainLanguage(models.Model):
language = models.CharField(verbose_name='Hauptsprache', max_length=40)
active = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'Hauptsprachen'
ordering = ['language']
def __str__(self):
return self.language
class SecondLanguage(models.Model):
language = models.CharField(verbose_name='weitere Sprachen', max_length=40)
active = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'weitere Sprachen'
ordering = ['language']
def __str__(self):
return self.language
class CustomUserprofile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(verbose_name='Vorname', max_length=40,
null=True, blank=True)
country = models.ForeignKey(Country, verbose_name='Land',
null=True, blank=True)
zipcode = models.ForeignKey(ZipCode, blank=True, null=True)
main_language = models.ForeignKey(
MainLanguage, verbose_name='Hauptsprache',
null=True, blank=True)
second_language = models.ManyToManyField(
SecondLanguage, verbose_name='weitere Sprachen',
null=True, blank=True)
class UserProfileForm(forms.ModelForm):
second_language = forms.ModelMultipleChoiceField(
queryset=SecondLanguage.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple)
class Meta:
model = CustomUserprofile
exclude = ('user',)