User defined fields model in django - django

I want to allow my users to define custom properties.
They are managing apartments so each customer manages the apartments in different way.
I want to allow them to define some custom properties for they apartments.
class Unit(CommonInfo):
version = IntegerVersionField( )
number = models.CharField(max_length=30,null=True, blank=True)
max_occupants = models.PositiveSmallIntegerField()
floor = models.PositiveSmallIntegerField()
rooms = models.PositiveSmallIntegerField()
is_disabled_access = models.BooleanField(default=False)
balcony_quantity = models.PositiveSmallIntegerField()
building = models.ForeignKey(Building)
recomended_price = models.DecimalField(max_digits=7, decimal_places=2)
I want them to be able additional fields to this model.
For example - is_breaker is_fuse Number_of
Since I cant predict what data they will require.
how can I do it?

I would reccomend the following solution:
1.Create a "property" Model:
class Property(models.Model):
property = models.CharField(max_length=140)
value = models.CharField(max_length=140)
def __str__(self):
return self.property
2.To your Unit model, add a ManytoMany field with property model:
class Unit(models.Model):
(...)
properties = models.ManyToManyField(Property)
3.Add an inline in your admin to view the different Properties:
class Unit(admin.ModelAdmin):
fields = ('__all__')
inlines = ('properties')

Related

How to use prefetch_related in django rest api with foreying key and heritage

I am working on this Django project, it uses heritage and foreign keys for its models.
These are the models:
class SetorFii(models.Model):
name = models.CharField(max_length=255)
class Asset(models.Model):
category = models.ForeignKey(
Category, related_name='categories', on_delete=models.CASCADE)
ticker = models.CharField(max_length=255, unique=True)
price = models.FloatField()
class Fii(Asset):
setor_fii = models.ForeignKey(
SetorFii, null=True, default=None, on_delete=models.CASCADE, related_name="setor_fiis")
Class Crypto(Asset):
circulating_supply = models.FloatField(default=0)
class PortfolioAsset(models.Model):
asset = models.ForeignKey(Asset, on_delete=models.CASCADE)
I would like to get the field setor_fii in the PortfolioAssetSerializer, That is what I tried without success.
I get this error message: Cannot find 'setor_fii' on PortfolioAsset object, 'setor_fii' is an invalid parameter to prefetch_related()
Would like some help to achieve that.
The serializer:
class PortfolioAssetSerializer(serializers.ModelSerializer):
category = serializers.CharField(source='asset.category.name')
setor_fii = serializers.CharField(source='asset.setor_fii.name')
class Meta:
model = models.PortfolioAsset
fields = (
'id',
'category',
'setor_fii'
)
The view
class PortfolioAssetList(generics.ListAPIView):
serializer_class = serializers.PortfolioAssetSerializer
def get_queryset(self):
return models.PortfolioAsset.objects.filter(portfolio_id=self.kwargs['pk']).prefetch_related('setor_fii')
To prefetch setor_fii, you will have to go through asset. Since Fii inherits from Asset, Asset will have an automatically created one-to-one field named fii. You can then use that to access setor_fii:
PortfolioAsset.objects.filter(
portfolio_id=self.kwargs['pk'],
).prefetch_related(
'asset__fii__setor_fii',
)
Also since the whole relationships here are just one to ones, you can use select_related instead of prefetch_related to get them all in one query (compared to three queries using prefetch_related):
PortfolioAsset.objects.filter(
portfolio_id=self.kwargs['pk'],
).select_related(
'asset__fii__setor_fii',
)

Export Inline ForeignKey entries from parent model using import-export in Django admin

So I'm trying to use import-export to export inline OrderEntries from the parent Order model in Django's admin into a csv or whatever. I don't want to have to register the inline model with Django (which works somewhat ok), but rather using the import-export's resources module, export directly from the parent Order model's list view in Django's admin. I couldn't find any way to do this in any of the Stack Overflow posts, and some of the other resources I googled.
I tried using the ForeignKeyWidget and fields module to allow me to do this, but when I export, no data is populated.
Here are my models:
class OrderEntry(models.Model):
order = models.ForeignKey(Order, related_name="order_entries", on_delete=models.PROTECT)
inventory = models.ForeignKey(Inventory, related_name="order_entries")
quantity = models.PositiveSmallIntegerField(default=1)
subtotal = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
class Order(models.Model):
user = models.ForeignKey(User, related_name="orders")
order_type = models.CharField(max_length=1, choices=ORDER_TYPE_STATUS_CHOICES, default='D')
payment_type = models.CharField(max_length=4, choices=PAYMENT_TYPE_STATUS_CHOICES, default='Cash')
class Inventory(models.Model):
description = models.CharField(blank=True, null=True, max_length=100)
quantity = models.IntegerField()
item = models.ForeignKey(Item, related_name="inventory")
class Item(models.Model):
name = models.CharField(max_length=40)
brand = models.CharField(max_length=40)
and my admin (I only have quantity as I was testing various ways to see if it would populate first):
class OrderEntryResource(resources.ModelResource):
quantity = fields.Field(column_name="Quantity", attribute="orderentry", widget=ForeignKeyWidget(OrderEntry, field='quantity'))
class Meta:
model = OrderEntry
fields = ('order', 'inventory', 'quantity', 'subtotal',)
class OrderEntryInline(admin.TabularInline):
model = OrderEntry
class OrderAdmin(ImportExportModelAdmin):
inlines = [OrderEntryInline]
resource_class = OrderEntryResource
admin.site.register(Order, OrderAdmin)
If at all possible, I'd like to include foreignkey fields for the User, Inventory, and Item models when I export also. Thanks so much!

Serialization and permissions in Django Rest Framework

I'm new in Django and DRF, have questions with serialization.
I have models:
class Commodity(models.Model):
shop = models.ForeignKey(Company, on_delete=models.PROTECT)
price = models.DecimalField(max_digits=10, decimal_places=2)
active = models.BooleanField(default=False)
class Clother(models.Model):
commodity = models.ForeignKey(Commodity, related_name='commodity', on_delete=models.CASCADE)
color = models.ManyToManyField(Color, related_name='color')
material = models.ManyToManyField(Material, related_name='material')
gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default=UNISEX)
class Outwear(models.Model):
clother = models.ForeignKey(Clother, on_delete=models.CASCADE)
name = models.CharField(max_length=30, blank=True)
outwear_type = models.ForeignKey(OutwearType, on_delete=models.CASCADE)
size = models.ManyToManyField(ClotherSize)
So I suppose to make a Serializer like that:
class OutwearSerializer(serializers.ModelSerializer):
commodity = CommoditySerializer(many=False, read_only=False)
clother = ClotherSerializer(many=False, read_only=False)
class Meta:
model = Outwear
fields = ('commodity', 'clother', 'name', 'outwear_type', 'size')
As I understand that read_only fields let me add or edit Outwear object further, but I supposed to have 2 types of permition:
All users can see only active Commodity objects.
Only Companies can create and edit their own objects.
Do I need to make 2 Serializer Models for read_only=True/False?
What is the best practice and where can I find good examples of something familiar?
I call User - unauthorized User. Company is authorized User.
Thanks!
For your first question:
class CommoditySerializer(ModelSerializer):
class Meta:
model = Commodity
fields = (shop, price)
Class CommodityActiveAPIView(generics.ListAPIView):
serializer_class = serializers.CommoditySerializer
queryset = Commodity.objects.filter(active=True)
second question is ambiguous. first define user role please

Django ManyToMany Validation Constraint

I have a ManyToMany link, and a Foreign key which links three objects.
[A]>--<[B]>---[C]
A can belong to many of B, and vice versa. However, A can only belong to B objects with the same parent C.
I'm trying to do something in the clean() method of the model. I'm using Django Rest Framework and no ModelForms or anything like that. I haven't been able to figure it out yet
Simplified Sample Code
class Device(models.Model):
name = models.CharField(max_length=20)
projects = models.ManyToManyField(Project, 'devices')
details = models.CharField(max_length=200)
serial = models.CharField(max_length=20)
address models.GenericIPAddressField(default="0.0.0.0")
port = models.IntegerField(default=3000)
jumpers = models.IntegerField(default=0)
install_date = models.DateField(blank=True, null=True)
class Project(models.Model):
name = models.CharField(max_length=20)
description = models.CharField(max_length=250)
area = models.ForeignKey(Area)
class Area(models.Model):
name = models.CharField(max_length=20)
description = models.CharField(max_length=250)
owner = models.CharField(max_length=20) # microservice doesn't have owner group - field in JWT
Serializers
class AreaSerializer(serializers.ModelSerializer):
class Meta:
model = Area
fields = ('name', 'description', 'owner')
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ('id', 'name', 'description', 'area')
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = Device
fields = ('id', 'name', 'projects', 'details', 'serial',
'address', 'port', 'jumpers', 'install_date')
I am not sure where and how do you want to validate your data. So I am just posting the method which can validate if a project can be linked to a device or not based on your specific check.
def validate_project(device, project):
projects = device.projects.all()
areas = set(projects.values_list('area', flat=True))
if len(areas) > 1:
raise serializers.ValidationError('projects are not valid')
return areas.pop() == project.area_id
EDIT:
You have to use a intermediate model for storing the relationship between device and project.
class Membership(models.Model):
device = models.ForeignKey(Device, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
area = models.ForeignKey(Area, on_delete=models.CASCADE)
use the above membership model to store the many to many relations.
On your device model use this field to define the many to many relation.
projects = models.ManyToManyField(Project, through='Membership')
checkout the docs
Now when you link a device and project you will have explicitly add the area id as well. Before adding now you can check if the project is valid or not based on the area associated.
(ignore the wonky field types, cba)
What it boils down to is: you need a table BC that stores relations between B and C. Table A would then select only from those relations through the intermediary m2m table ABC (or ditch ABC, couldn't figure out how to draw m2m with the online tool). I think I mixed up B and C in this picture, swap them around depending on whether B or C holds the ForeignKey.
Please correct if I'm wrong!

Django admin: ordering inline based on FK'd property

I've got a simple Django photography competition app that has three simple model definitions:
class Person(models.Model):
name = models.CharField(unique=True, max_length=255)
id = models.AutoField(primary_key=True)
class Meta:
db_table = u'people'
def __unicode__(self):
return self.name
class Round(models.Model):
theme = models.CharField(max_length=255)
number = models.IntegerField()
id = models.AutoField(primary_key=True)
class Meta:
db_table = u'rounds'
def __unicode__(self):
return self.season.name+" - "+self.theme
class Entry(models.Model):
rank = int
total_score = models.SmallIntegerField()
id = models.AutoField(primary_key=True)
person = models.ForeignKey(Person, db_column='person')
round = models.ForeignKey(Round, db_column='round')
A Round has multiple Entry objects, and each Entry has one Person. One Person can obviously have multiple Entrys into different Rounds.
In the admin view, I'd like to be able to select a Round and see the details of the Entry items inline. This I can do with the following:
class EntryInline(admin.TabularInline):
model = Entry
fields = ['comments','person','total_score','image']
readonly_fields = ['person','image']
extra = 0
class RoundAdmin(admin.ModelAdmin):
fields = ['theme','number']
inlines = [EntryInline]
However, this sorts the Entry seemingly arbitrarily. I can use django's new ordering keyword in the EntryInline class to specify the ordering should be on the person, but this orders by the person Id property and not their name property.
How would I order this inline on the FK'd Person.name property?
Add this in the EntryInline class:
ordering = ["person__name"]