Defining dependent Django Model Fields - django

I have to define a model where one of the fields depends on the other.
I am storing commodity trades, and the grades of the commodities vary based on the kind of commodity. For example if I store a coal and an iron trade I need to specify what is the quantity of each grade being traded.
Example:
{'Grade–I':500, 'Grade-II':1000, 'Washery-Grade-I':0, 'Washery-Grade-II':0, 'Washery-Grade-III':100}
{'Fe 65%+':10, 'Fe 60-65%':55,'Fe 55-60%':0}
One possible approach is storing the commodity type as a CharField with choices and serializing the the grade quantity and storing it as a JSONField.
class TradeRetail (models.Model):
commodity_type = models.CharField(max_length=5, choices=(('CO','COAL'),('IO','IRON-ORE'),('WTI','WTI'),), blank=False)
grade_quantity = JSONField()
My questions are:
a) Is this the neatest way to create a Model?
b) How do I define the relationships between grade_quantity and commodity_type to generate appropriate forms to obtain user inputs?
c) Will all the custom validations I write sit in the clean() function?

If I get correctly your problem, I think it would more "Django-compliant" to define two models: one containing the commodity_type, and one containing the grade_quantity. Then, you can create a foreign key in commodity_type to link it with grade_quantity.
As general documentation, you may read https://docs.djangoproject.com/en/1.7/topics/db/examples/one_to_one/
Exemple:
class Commodity (models.Model):
type = models.CharField(...)
quantity = models.ForeignKey('Commodity')
class Grade (models.Model):
type = models.<your type adapted to the grade quantity field>
Warning: I haven't test this exact example, but it looks like what you're trying to achieve. Have a look at the page https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey
For your questions:
a) For tips on how to create models, see the first links with OneToOne examples. Usually, it is useful to add a str(self) function for displaying correctly the name of the model instance. Read carefully the examples in Django documentation to have tips about how to correctly write your model (usually you define first the fields, then the methods of the models, and often the str method).
b) The ForeignKey field is the link between two models (oneToOne). A ManyToMany link exists also with the ManyToManyField field (see https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/)
c) Normally: yes. The example I propose may need you to write on a different way the validation you already developed.

Related

bulk create in django with foreign key

Models:
class Author(Base):
name = models.CharField(max_length=100, unique=True)
class Book(Base):
name = models.CharField(max_length=100, unique=True)
class AuthorBookAssn(Base):
author = models.ForeignKey(Author, on_delete=models.PROTECT)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
I have an api to create a book, and along with the book data we would also get a list of author ids.
Now for each book we need to create one/more records (depending on the author ids provided) in the AuthorBookAssn table.
What is the best way to do this and can the create be done in bulk.
Currently the approach is to get the author objects for each of the ids in the list and then call
AuthorBookAssn.objects.create(book=book_instance,author=author_instance)
You've created a many-to-many relationship so your current method is the only possible way based on your current structure. If you were to use Django's in-built m2m field then you would essentially do the same except you would do something like author.books.add(book), but again, you would have to do this separately to your book/author creation. An alternative would be to use a many-to-one relation (i.e. ForeignKey field) which would allow you to connect the two when an object is created. Many-to-One might not be how you want to structure things if books can have multiple authors and vice-versa.
(supplementary to OsVoid's answer)
There might be some degree of optimization by working with the object ids (primary key values) rather than fetching the entire objects. Premature optimization is a bad idea, and you'd have to benchmark this idea to see if any improvement is measurable (assuming you have any need to optimize at all).
Given book_pk and author_pk you can use the "magic" _id suffix:
AuthorBookAssn.objects.create(book_id=book_pk,author_id=author_pk)
And instead of fetching whole objects, you might fetch just their pk values using a .values_list('pk') in a queryset. (with flat=True if only the one value is being requested). Since this is just a number, it also might be possible to attach it to some other objects that you really do need to obtain, using annotation.
Also, you can cause your own model to be used for the association in a Django ManyToMany relation, using "through". This is valuable if you want to store extra information about the association, such as when it was created, who by, for what purpose, etc.

Django - Many to Many Relationship with Workouts & Exercises

I'm currently stuck on how to do the following:
I want to track workouts and see the progress being made with the exercises.
Each workout has a name, body weight, date, and exercises.
I want to select the exercises when adding the workouts(exercises are already pre-created with a name and some tags), however, each workout is different, meaning the reps, sets, and weight for the exercise is different every time.
I'm not sure how to make a model for this.
I've added an image of a simple design I made to show what I'm after
Hope someone can help me, I'm pretty sure it's a simple solution however, my brain is stuck atm.
Image Of Design
First an foremost, I'd recommend reading through the Django models docs to get an idea of what models represent and how they work.
To address your question, I think you've correctly identified all of the information you need to create your models, so let's go through them step by step.
Architecture
It's helpful to take a step back and think about the entities in your app. Identify what they are, what attributes they posses and which of these attributes are atomic i.e. cannot be their own entity.
Workout - You mentioned that you want to track workouts with each one having name, body weight, date, and exercises. All of these attributes except for exercises seem to be atomic as they can be represented with fundamental datatypes (strings, floats, datetimes etc.). Moreover, one workout can have many exercises indicating that we need to abstract it into its own entity.
Exercise - You identified that exercises are pre-set and need to have a name and tags. A name is something we can represent with a string, however one exercise can have multiple tags, meaning it's not atomic (has a one-to-many relationship). This means we need to extract it into its own entity.
Tag - From what you said, a tag simply has one attribute which is a name that can be represented by a string. One tag can belong to many exercises.
You may be wondering where we are storing the reps, sets and weight data for each exercise in each workout. This is actually going to require an extra entity that stores the many-to-many relationship between Exercise and Workout. Let's call this Workout-Exercise.
With this information we could draw a Entity Relationship Diagram as such:
This gives us what we need to start creating Django models.
Models
Let's start with the Exercise and Tag entities. We can simply translate these directly into Django models:
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=200)
class Exercise(models.Model):
name = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag)
Here we've created the two models and specified a many-to-many relationship between Exercise and Tag. This means that an Exercise object can have many Tag objects e.g. you can call exercise.tags.all() to get all of the tags for a given Exercise object.
The tricky part comes when we are creating the Workout-Exercise entity. When we use ManyToManyField in Django, it normally automatically creates a mapping model/table that we don't see. However, in the case where we want to store extra information about these relations (as we do in our use-case) we have to use a through model.
On this model we have to define the two foreign keys for the models we are linking along with the data types for the extra field data we want to store. In this case the foreign keys are Workout and Exercise, and the extra data are reps, sets and weight. The model definitions could therefore look like:
class WorkoutExercise(models.Model):
workout = models.ForeignKey(
'Workout',
on_delete=models.CASCADE,
)
exercise = models.ForeignKey(
Exercise,
on_delete=models.CASCADE,
)
reps = models.IntegerField()
sets = models.IntegerField()
weight = models.DecimalField(max_digits=5, decimal_places=2)
class Workout(models.Model):
name = models.CharField(max_length=200)
body_weight = models.DecimalField(max_digits=5, decimal_places=2)
date = models.DateTimeField(auto_now_add=True)
exercises = models.ManyToManyField(
Exercise,
through=WorkoutExercise
)
If you're confused about any of the model data type choices I've recommended, please take a look at Django model docs.
With this set-up you should be able to access and insert all of the data you need. If you need more information on how to access any of the many-to-many relationship data, please look at the Django many-to-many docs.
Sources
https://docs.djangoproject.com/en/3.2/topics/db/models/
https://www.1keydata.com/database-normalization/first-normal-form-1nf.php
https://en.wikipedia.org/wiki/One-to-many_(data_model)
https://docs.djangoproject.com/en/3.2/topics/db/examples/many_to_many

How to relate two different django models into on many to many field form another one?

I'm trying to find a solution to the following problem with django models:
The app would add products to a shopping cart. The problem is that those products come from different models, and no matter where they come from, I'd like to use one ManyToManyField to incorporate them.
Suppouse I've two different kind of products from two different models:
Class ListOfProducts1(models.Model):
name= CharField()
price= IntegerField()
Class ListOfProducts2(models.Model):
name=CharField()
price=IntegerField()
The following model would be used for get the quantity and the product added(and then related to one particular order).
Here is the problem. Look to the field itemsadded, where I want to relate this field to ListOfProducts 1 and 2. I'd put both of them into the same field, but I've already know this is not possible. Just for better understanding of the problem here you have:
Class ProductsOrdered(models.Model):
itemsadded= OneToOneField(ListOfProducts1 and ListOfProducts2,on_delete=models.CASCADE)
Quantity = IntegerField()
Then the Order's model:
Class Orders(models.Model):
cart= ManyToManyField(ProductsOrdered)
The OneToOne fields can refer to only one table.
But you can use either GenericForeignKey or alternatives (which is better).
Look at this article: Avoid Django’s GenericForeignKey. It describes alternatives, such as:
nullable fields on source table
intermediate table with nullable fields
intermediate table with OneToOneFields on destination models
multi-table inheritance
multiple linked models

Displaying all fields of Foreign Key Model

What I want is to retrieve all the fields belonging to a Model of a foreign key.
My models for example:
class BaseProduct(models.Model):
name = models.CharField(max_length=256)
variant = models.CharField(max_length=256, default='N/A')
type = models.ForeignKey(ProductType)
class ProductType(models.Model):
name = models.CharField(max_length=256,blank=False,null=False)
sofa = models.ForeignKey(SofaProduct, blank=True, null=True)
toaster = models.ForeignKey(ToasterProduct, blank=True, null=True)
These are just examples, there can be any number of ProductType models each with any number of fields.
In my template I can display all the fields of the BaseProduct by using the BaseProduct ID. What I want is to display all the fields of the FK.
For example if type = sofa in BaseProduct, I need to retrieve and display all sofa fields as well as BaseProduct fields.
(disclaimer: I have a tendency to give really long answers. You'll have to forgive me for that)
First rule of schema design - It should reflect your real world business logic (not the actual business action mind you, just the implications of the relationships). For example, if I have a class Person I can create a class Pet with a foreginKey to Person which translates to - every person can have multiple pets.
If we apply that logic to your schema we see that ProductType is a class that has a foreignKey to both Sofas and Toasters, which means each Toaster can have multiple Sofas and vice versa. Last time I checked, I never heard of a Sofa that had a Toaster.
In other words - you need to think what you're actually trying to achieve here. I'm guessing BaseProduct is a basic class that has common fields, and Sofa and Toaster are different types of products. Since they are different, they have their own special fields, and shouldn't be related, so it makes sense to have them as separate models. So why do you even need ProductType? To define the name Toaster? You're already defining an entire model! Why do you need to keep its name on a different table (and not, say, some custom method that always returns "I am a toaster, hear me roar")?
My best guess is that you want to be able to define new types of products on the go. However, if you intend to keep them separated on the model level, then you'll have to create a model for each new product. And if you want to be able to simple define a new model with ProductType, then you either need to have one Product class to manage them all, or you want a complicated dynamic system that can create new models on the fly.
Let's break those options down:
Create a generic product and a type class, like you did there:
class ProductType(models.Model):
name = models.CharField(max_length=256,blank=False,null=False)
class Product(models.Model):
name = models.CharField(max_length=256)
variant = models.CharField(max_length=256, default='N/A')
type = models.ForeignKey(ProductType)
Now each product can only be of one type, and you can always create new types on the go. This of course means all Product objects will share the same fields, and is very limiting. You won't have the same flexibility for each type like you would before (no sofa-only fields), but on the other hand it will be easier to create dynamic types of objects - you just define a new ProductType and bam you have a whole new group of products.
Create a basic abstract Product model, and define a new sub-model for each new type of product. You'll have a lot more flexibility for each one, but defining new types will always require defining a new model and setting up a table for it. With this scheme you don't need the ProductType object at all because the different models define the different types (there's no need for duplicity).
You can create some kind of admin page for the process, but it's not going
to be very easy to setup, and you might find yourself eventually with too many tables
(which can be especially problematic if you need to sometimes query
on all products - you'll have to join a lot of different tables,
which is not very efficient).
Use a non-relational database with some dynamic-models know how and disco*
*ok, it's actually more complicated than that, but the explanation on how to combine them is way too long, even for my answer. If it seems over your head, forget about it. If you have some idea about how non-relation databases work, you can probably figure it out yourself
Your question is somewhat unclear.
I think you want Django modal forms to display all fields of an modal.
def ListForm(Forms.form):
model = MyModel
fields='__all__' #Sets display all
fk_name ="Model_to_use" #Is needed when your model has more then one fk
Django model form
You can use _set for accessing related objects. For example, if you have two models like these:
class MyModel(models.Model):
name = models.CharField(max_length=200)
somedata = models.CharField(max_length=200)
class AnotherModel(models.Model):
name = models.CharField(max_length=256,blank=False,null=False)
referral = models.ForeignKey(MyModel)
type = models.CharField(max_length=256,blank=False,null=False)
you can access the name field of AnotherModel with
>>> m = MyModel.objects.get(id=1)
>>> m.AnotherModel_set.all()[0].name
See: https://docs.djangoproject.com/en/dev/topics/db/queries/#related-objects
On a side note, you should probably rethink your models structure, as yuvi pointed out.

Model design question: custom fields at runtime?

I have some newbie questions about Django.
I want to write a generic ticket-management system, where the administrator of the site should be able to add custom fields to a ticket. It seems that the database tables are generated on initialization, so it is not clear to me how to add custom fields at runtime.
One way is to have a long list of fields of different types, all nullable, and let the administrator rename/select the fields she needs. Is there a better design?
Thanks!
I'm currently in charge of maintaining a similar site where a treatment for a medical condition is listed and there can be arbitrary number of "cases" which are user-posted experiences for that treatment/condition combo attached.
The method my company used to set it up was to have an Entry object which would be analogous to the custom field you described, which has a Foreign Key referencing the treatment/condition to which it belongs.
Then when we want to get all the entries for a particular treatment/condition combo, we simply do an
Entry.objects.filter(condition=ID)
So, in your case, I would suggest having a Ticket model, and an "Entry" style model which contains a Foreign Key reference to the Ticket to which it belongs.
I would make something like the code below. Store extra attributes in an attribute model. Store the values in AttributeValue.
class Ticket(models.Model):
name = models.CharField(max_length=200)
class Attribute(models.Model):
name = models.CharField(max_length=200)
class AttributeValues(models.Model):
attribute = models.ForeignKey(Attribute)
ticket = models.ForeignKey(Ticket)
value = models.CharField(max_length=200)