I would like to create a custom field with choices that store data in n (number of choices) db columns. It's should looks like dummy vector.
Example:
Choose type of product
This product in db table
id
kind_hygine
kind_road_equipment
kind_relax
kind_food
1
0
0
1
0
It is a legacy db, so I can not change db tables layout.
How can I achieve it?
try this
model.py
YOUR_CHOICES = [
("Road equipment","Road equipment"),
("Relax","Relax"),...
#it goes like this create list inside it create tuples as many as you want
#inside every tuple create 2 string elements the first is one will be
#stored inside your DB the seconde is the one will be shown to the user
]
class YourModel(models.Model):
.... #other model fields
your_choices_field= models.CharField(choices=YOUR_CHOICES)
now in your form
class YourForm(forms.ModelForm):
your_choices_field=forms.ChoiceField(choices=YOUR_CHOICES)
Related
Let's say I have these models:
class Material(models.Model):
name = models.CharField([...])
class Consumable(models.Model):
name = models.CharField([...])
restores = models.IntegerField([...])
class Weapon(models.Model):
name = models.CharField([...])
damage = models.IntegerField([...])
# And then I have an 'inventory', like this one:
class Inventory(models.Model):
user = models.ForeignKey([...]) # to which user you want to link the item
item = models.ForeignKey([...]]) # which item
quantity = models.IntegerField([...]) # how many of it
I want to be able to have all Material, Consumable, and Weapon models listed in the 'item' field, so when you want to add an item as an inline, you would see all 3 models' objects.
Something like
# instead of this
item = models.ForeignKey(Consumable) # which item
# want something like this
item = models.ForeignKey(Consumable and Material and Weapon) # which item
# this wouldn't work ofc...
Is there a way to collect all 3 of them and pass them to the 'item' field, without the need of restarting the server? (when making a "choices" list that queries from a model you must restart the server to see the newly added objects, I don't want that.)
I also want to stick to the built-in admin of Django since it provided everything I need for the past couple of months, but I am open to any ideas.
I could be wrong but I think you are making this more complex than it needs to be. Instead of doing separate classes for materials (type of material) and consumable (type of product), you can have that built in the last class as model field as category or bolean fields.
class Products(models.Model):
material_type =
consumable = boolean for yes no or you can do multiple choice field
Then for items you can query the number of items based on material_type or consumable model fields (see query filters for for more).
all_items = Products.model.all()
consumable_items = Products.model.filter(your filter logic goes here)
Hope this helps!
These are my models:
from django.db import models
class A(models.Model):
# fields
class B(models.Model):
a = models.ForeignKey(A)
# fields
I have some items from model A:
items = A.objects.filter(some_column=some_value)
Now I want 2 model B objects for each object in items. If there are 5 objects in items then I want total 10 objects from model B, 2 model B objects for each object of model A. Hope I made my requirement clear. I tried some queries, but ended up with querying model B for each model A object.
Also the solution should be well optimized, I would like to avoid 20 different queries for 20 objects in items.
If it is not possible with ORM, then I can use raw query as well.
you can get those using related query and prefetch_related
like
items = A.objects.prefetch_related('b_set').filter(some_column=some_value)
for item in items:
/* Here you get all modal B object for particular item */
obj_of_modal_B = item.b_set.all() # Here b is model name in small
you can also overwrite related_query name using related_name
class A(models.Model):
# fields
class B(models.Model):
a = models.ForeignKey(A,related_name='custom_name')
# fields
and then use like
items = A.objects.prefetch_related('custom_name').filter(some_column=some_value)
for item in items:
/* Here you get all modal B object for particular item */
obj_of_modal_B = item.custom_name.all()
Use prefecth_related. It won't query in for loop. It will have two query only
a = A.objects.prefetch_related('b')
Read about prefetch_related in docs for more detailed information
https://docs.djangoproject.com/en/3.0/topics/db/queries/
I am using Django to interface with another (JAVA) application that based on some events generates at runtime tables in the db with the same model. So I don't have a direct control over the DB. For example:
Sensor1
id | value | time
1 10 2018-10-11
Sensor2
id | value | time
1 12 2018-10-11
Currently, my Django model is looking something like this:
class Sensor(models.Model):
value = models.IntegerField()
time = models.DatetimeField()
class Meta:
managed = False
db_table = "Sensor1"
Do you have any clue if I can set the model somehow to be able to gain the data from a different table based on the query?
Ideally, something that would allow me to get the data in the fashion of:
config_tables=['Sensor1','Sensor2']
for table in config_tables:
data = Sensor.objects.table(table).objects.all()
...
Other possibility might be also to have a SQL query that executes on different tables, so perhaps something like:
SELECT * FROM %s;
It seems that the best solution so far is to make a custom SQL Query so in this example it could be something like this in models.py:
def get_all_parameters(db_table):
return Parameters.objects.raw('SELECT * FROM %s' % db_table)
and call it as:
get_all_parameters('Sensor1')
or as:
TABLES = ['Sensor1', 'Sensor2']
for table in TABLES:
parameters = get_all_parameters(table)
...
So I have models like so:
class Leaderboard(models.Model):
pass
class Column(models.Model):
leaderboard = models.ForeignKey(Leaderboard, related_name="columns", on_delete=models.CASCADE)
related_columns = models.ManyToManyField(self)
index = models.PositiveIntegerField()
And serializers like so:
class ColumnSerializer(ModelSerializer):
related_columns = serializers.PrimaryKeyRelatedField(queryset=Column.objects.all(), many=True)
class Meta:
model = Column
fields = ('leaderboard', 'related_columns', 'index',)
class LeaderboardSerializer(ModelSerializer):
children = ColumnSerializer(many=True)
class Meta:
model = Leaderboard
fields = ('columns',)
So what I'd like to do is verify that any columns added to related_columns for ColumnSerializer already belong to its Leaderboard parent. I have tried many times to access the Leaderboard or a Leaderboard ID (like by manually specifying id in fields) during creation of the ColumnSerializer to verify, but LeaderboardSerializer` is not initialized before Column so I cannot verify the details.
Basically, I want to modify queryset=Column.objects.all() to be queryset=self.instance.leaderboard.columns.all()
However I don't have access to Leaderboard inside Column. For example, if I access self.parent.instance/initial inside ColumnSerializer it is None until inside Leaderboard.validate_columns(). One thing I've thought of is to just do the validation on the Leaderboard side, but I still think it should be "doable" to do this validation inside Column in case I ever want to edit those directly, without first going through a Leaderboard...
Here is how I solved this problem:
def validate_columns(self, columns):
if not columns:
raise serializers.ValidationError("Leaderboards require at least 1 column")
# Make sure all column indexes are unique
indexes = [column['index'] for column in columns]
if len(set(indexes)) != len(columns):
raise serializers.ValidationError("Columns must have unique indexes!")
# Make sure all column keys are unique
keys = [column["key"] for column in columns]
if len(set(keys)) != len(columns):
raise serializers.ValidationError("Columns must have unique keys!")
# Validate that column.computation_indexes points to valid columns
for column in columns:
if 'computation_indexes' in column and column['computation_indexes']:
for index in column['computation_indexes'].split(","):
try:
if int(index) not in indexes:
raise serializers.ValidationError(f"Column index {index} does not exist in available indexes {indexes}")
except ValueError:
raise serializers.ValidationError(f"Bad value for index, should be an integer but received: {index}.")
return columns
I make sure that the columns are unique (both in their keys and indexes) and that the columns they are referencing exist as well.
I have model with field named "number". It's not the same as id, it's position while displayed on website, users can sort teams around.
I need something for default property of number. I think I should just count the number of positions in the database and add one, so if there are 15 positions inside db, the new team would be last on list and have "number" 16.
But I don't know how to do it, inside models.py file.
Inside views.py I would just use
Iteam.objects.count()
But what can I use inside model declaration? How can the model check itself?
Edit:
I tried do it as Joey Wilhelm suggested:
from django.db import models
class ItemManager(models.Manager):
def next_number(self):
return self.count() + 1
class Iteam(models.Model):
name = models.CharField()
objects = ItemManager()
number = models.IntegerField(default=objects.next_number())
Unfortunetly i get error:
AttributeError: 'NoneType' object has no attribute '_meta'
This is actually something you would want to do on a manager, rather than the model itself. The model should represent, and perform actions for, an individual instance. Whereas the manager represents, and performs actions for a collection of instances. So in this case you might want something like:
from django.db import models
class ItemManager(models.Manager):
def next_number(self):
return self.count() + 1
class Item(models.Model):
number = models.IntegerField()
objects = ItemManager()
That being said, I could see this leading to a lot of data integrity issues. Imagine the scenario:
4 items are created, with numbers 1, 2, 3, 4
Item 2 gets deleted
1 new item is created; this item now has a number of 4, giving you a duplicate
Edit:
The above approach will work only for pre-generating 'number', such as:
Iteam.objects.create(number=Iteam.objects.get_number(), name='foo')
In order to have it work as an actual default value for the field, you would need to use a less savory approach, such as:
from django.db import models
class Iteam(models.Model):
name = models.CharField()
number = models.IntegerField(default=lambda: Iteam.get_next_number())
#classmethod
def get_next_number(cls):
return cls.objects.count() + 1
I would still warn against this approach, however, as it still could lead to the data integrity issues mentioned above.