I am trying to make an application for a restaurant in django; I have to create a menu for different types of items, and all of those different types of items have to essentially be a product, so that I can add that product to a user's corresponding cart. Here are my menu items:
from django.db import models
from django.contrib.auth.models import User
class Product(models.Model):
price = models.DecimalField(decimal_places=2, max_digits=10)
class Pizza(Product):
pizzatype = models.CharField(max_length=15)
extras = models.TextField(max_length=50)
size = models.CharField(max_length=10)
class Subs(Product):
name = models.TextField(max_length=64)
size = models.CharField(max_length=10)
class DinnerPlatters(Product):
name = models.TextField(max_length=64)
size = models.CharField(max_length=10)
class Pasta(Product):
name = models.TextField(max_length=64)
class Salads(Product):
name = models.TextField(max_length=64)
As can be seen, I tried deriving the models for different types of menu items from a single model Product, but while running makemigrations, I get the following message on the terminal:
You are trying to add a non-nullable field 'product_ptr' to dinnerplatters without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
I tried googling the solution to my problem, but couldn't find an approriate solution.
I am new to Django and this is my first application, so any help or any other method on how to approach my problem would be kindly appreciated.
As your models inherit from the Product's model, you are using Multi-table inheritance. Now that Multi-table inheritance automatically creates OneToOneField as classname_ptr between inheritance model and base model, your models which is inherit from product's model has product_ptr field. As your model has product_ptr field, you should add default value for existing rows which is save before by you.
https://docs.djangoproject.com/en/3.0/topics/db/models/#multi-table-inheritance
Related
I dont understand Django Intermediary models at all. Let's say that i want to add one more additional field to User model, and store relationship between two users in another model(intermediary) like this:
class Contact(models.Model):
user_from = models.ForeignKey(User...)
user_to = models.ForeignKey(User...)
...
And the field i want to add is:
following = models.ManyToManyField('self',
through=Contact,
related_name='followers',
symetrical=False)
What really happen when i call user_object.followers.all() and what is the difference between user_object.following.all() are they both the same?
I'm new to the whole Django thing and a bit lost. Sorry if the title is a bit confusing I'll try to clear things out.
So basically I have two models (Folder and Document). A Document can have a single Folder as one of its fields using a Foreign Key. Now I have another field in Document that needs to get the value of the total Document objects that share the same Folder and increase by one.
I've tried things I read on the docs (aggregation, F() objects, overriding model's save() function) as well as some answers is read here but didn't manage to get it right so I'm posting to get some help. Below is my models.py file with the two models and some comments for better understanding.
class Folder(models.Model):
category = models.IntegerField()
subCategory = models.IntegerField()
name = models.CharField(max_length= 50)
desc = models.TextField()
class Document(models.Model):
folder = models.ForeignKey(Folder, on_delete=models.CASCADE)
date_created = models.DateField()
date_added = models.DateTimeField()
#The field below needs to sum all Document objects that share
#the same folder value in the database + 1 and set it as its default value
f_no = models.IntegerField(default=lambda: Document.objects.aggegate(Count('folder')) + 1)
Thank you in advance, any leads or clues are most welcome
EDIT:
Forgot to say that all management is done via Django's admin dashboard
if this has anything to do at all with my situation. I registered both
models in admin.py and that's all. I make new Folder objects when needed
and save Documents with one specific Folder in them each time
I would recommend creating a ManyToMany relation in the Folder, and add a created Document object into the Folder's ManyToMany relation.
Models.py
class Folder(models.Model):
category = models.IntegerField()
subCategory = models.IntegerField()
name = models.CharField(max_length= 50)
desc = models.TextField()
documents = models.ManyToManyField('app.Document')
You can add can add documents to the folder by using .add() to the ManyToMany relation and the amount of documents in the relation by using .count()
ManyToMany relations are well documented here:
https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/
When you create a Document model object, it represents a single item. That single item shouldn't have a count of how many documents are in a file. The f_no you note should actually be in the Folder model.
Once you create a Document object that is related to a Folder object via ForeignKey, you can use signals to increment the f_no field that resides in the Folder object.
#receiver(post_save, sender=Document)
def increment_folder_item_count(sender, **kwargs):
# get Folder object via Document model instance folder foreignkey field
# folder.f_no += 1
# folder.save()
I know this is a very basic question. I am learning django and i see the most important part is ForeignKey field and ManyToManyField. They are used ubiquitously. Without understanding those two, a proper model cannot be designed. If i have to design a model with FK relation, i always have to see the example first and try to come with the solution. I cannot confidently design a model cause i have not understand this well. It would be great if someone make me understand so that the picture comes to my head what is FKField, how FKField and MTMField are generated in table with simple english(Language is one of the barrier for me to understand from the documentation).
Here is the model for foreign key
class Category(models.Model):
name = models.CharField()
class Product(models.Model):
name = models.CharField()
category = models.ForeignKeyField(Category, related_name="product")
In django, you can add one instance of a "variable" as a part of a table: That is a ForeignKey.
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=30)
category = models.ForeignKey(Category)
class Category(models.Model):
name = models.CharField(max_length=30)
Here, you will have a SQL table named "[NAME OF YOUR APP]_product" that will have two columns: "name" and "category_id".
You will have an other table named "[NAME OF YOUR APP]_category" that will contain one column "name".
Django will know that when you load a Product, it will have to get its category_id, and then get that element from the category table.
This is because you use a foreignkey: it is one "variable". And it is "Many to One" because you can have many Products having the same Category.
Then you have "Many to Many". Here you can have more than one "variable"
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=30)
category = models.ManyToManyField(Category)
class Category(models.Model):
name = models.CharField(max_length=30)
Here, the difference is that you will get a table named "[NAME OF YOUR APP]_product" with only one column: "name".
Next to that, you will have a table "[NAME OF YOUR APP]_product_category", that will have the columns "product_id" and "category_id".
And one last table that will be "[NAME OF YOUR APP]_category" that will have one column: "name".
The way it works is that Django will get the Product, and see that it have a ManyToMany field of Category.
It will go to "[NAME OF YOUR APP]_product_category" and get the list of ids for the product_id you need, and get them from "[NAME OF YOUR APP]_category".
This is Many to Many because you can have a lot of Products that have each lots of different Category.
If you still don't understand, I will edit this post to add a SQL example of what the database looks like.
(Sorry, this is not really pleasant to read and a really broad way to explain how Django handle things, but I tried to do short and simple statements.)
Using Django we have two types of Users (Teachers and Students) with common fields and uncommon fields
In our wizard we first POST the common fields to /users with an extra type_field
Every operation after this should be able to figure out which model (Teacher or Student) it needs to use.
We are thinking of making two models ( Teacher and Student ) with an one-to-one field.
But how do we hookup the type_field to the right Model on every operation?
You dont have to go for an extra field since you are already having two different classes for students and teachers. A simple approach may looks like below.
from django.contrib.auth.models import User
class Teacher(User):
extra_field_1 = models.Fieldtype()
...
...
class Student(User):
extra_field_1 = models.Fieldtype()
...
...
You can provide both type of users same registration form and upon clicking next take them to next page based on the value of I am a teacher/student field. In that case I suggest you to use atomic blocks if you dont want to save data in case registration procedure fails at some point or user have selected a wrong choice and they want to go back. By this approach each inherited models have username, first_name, last_name and email that you dont have to insert any of these to Teacher or student model.
Then you have to create forms for each model. You may use modelform A much better approach will be using class based views since that reduce a lot of code and stick to dry principles.
You may use something like:
class Person(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
# more common fields
class Student(Person):
specific_field_to_student = models.CharField(max_length=255)
# more fields
class Teacher(Person):
specific_field_to_teacher = models.CharField(max_length=255)
# more fields
In your database you will have 3 tables (yourapp_person, yourapp_student and yourapp_teacher). Now, if type_field value is student, you will use Student model to create user, if it is teacher, you will use Teacher model.
Note: You may need to make Person model above a subclass of the built-in User model.
Edit:
I have edited the model above to take into account the requirements in the comments below.
Now, to retrieve user by id, you can use the following code in your view:
user = Person.objects.get(id=id) # id is the view param
if hasattr(user, 'student'):
print("Student")
else: # hasattr(user, 'teacher')
print("Teacher")
Gurus:
I have a very simple data model relating two different kinds of Users via an Interaction:
# myapp/models.py
class C1(models.Model):
user = models.ForeignKey(User)
class C2(models.Model):
user = models.ForeignKey(User)
class Interaction(models.Model):
c1 = models.ForeignKey(C1)
c2 = models.ForeignKey(C2)
date = models.DateField()
So, an Interaction has a User of class C1, a User of class C2, and a date (in addition to the primary key, automatically an integer); a given pair of users can have many Interactions.
I populated the database with 2000 random Users (1000 each class), and when I query the Interaction the run time is too slow (about three seconds - unacceptable in production environment).
Is there something I can do to improve the run time of this search? Should I define the Interaction differently?
Thanks.
If you'd like to store additional information related to your users, Django provides a method to specify a site-specific related model -- termed a "user profile" -- for this purpose.
To make use of this feature, define a model with fields for the additional information you'd like to store, or additional methods you'd like to have available, and also add a OneToOneField from your model to the User model. This will ensure only one instance of your model can be created for each User. For example:
# settings.py
AUTH_PROFILE_MODULE = 'myapp.UserProfile'
# myapp/models.py
class UserProfile(models.Model):
CLASS_CHOICES = (
(0, 'Yellow User'),
(1, 'Green User'),
)
user_class = models.IntegerField(choices=CLASS_CHOICES)
user = models.OneToOneField(User)
class Interaction(models.Model):
u1 = models.ForeignKey(User, related_name='u1s')
u2 = models.ForeignKey(User, related_name='u2s')
date = models.DateField()
Creating a new model and associated table for each User class seems not like good design.
You have used foreign keys to associate C1, C2 with Users, and called this a one-to-many relationship. However, the relationship between Interaction C1, C2 is not one-to-many because one Interaction can be associated with many Users, and one User can also have many Interactions associated with it. This is called a many-to-many relationship, and is represented in Django models using models.ManyToManyField.
So try changing your models.py file to -
class Interaction(models.Model):
ic1 = models.ManyToManyField(C1)
ic2 = models.ManyToManyField(C2)
date= models.DateField()
See if this helps...