Category: 3. Models

https://static.vecteezy.com/system/resources/previews/024/159/829/non_2x/3d-modeling-icon-or-symbol-in-teal-and-white-color-vector.jpg

  • Update Model

    Django’s ORM API provides useful functionality for performing CRUD operations on the data stored in the tables of relational databases.

    The create(), update() and delete() methods perform their respective operations on an already existing table. However, you often need to make changes to the model structure itself, by adding, deleting or altering the attributes of the model. Django’s admin interface can be helpful in handling these activities.

    The Migration System in Django

    Django has a powerful migration system that deals with the process of updating a model.

    Django propagates the changes you make to your models (adding a field, deleting a model, etc.) into your database schema with the help Migrations mechanism. The migrations-related commands are executed with the manage.py script.

    The following commands are available −

    • migrate − Responsible for applying and unapplying migrations.
    • makemigrations − Responsible for creating new migrations based on the changes made to the models.
    • sqlmigrate − Displays the SQL statements for a migration.
    • showmigrations − Lists a project’s migrations and their status.

    When you first set up a Django project, it automatically installs certain apps. They are listed in the INSTALLED_APPS section in the settings.py module.

    Most of these apps are used in the admin interface to create and manage the users, groups, authorization, etc., and the data related to these apps is stored in the respective tables.

    We need to run the following migrate command for the first time to create the table structure required for INSTALLED_APPS −

    python manage.py migrate
    

    Running the above command will create a package called migrations inside the app package folder. All the subsequent migration scripts are stored in it.

    Subsequently, when you create a new app (with startapp command), you also need to add it in the INSTALLED_APPS list. Next, you declare the models required for the new app. Here, you need to create the database tables required for the new app.

    The makemigrations Command

    Let us add a new model in the models.py module as follows −

    from django.db import models
    
    # Create your models here.classDreamreal(models.Model):
       website = models.CharField(max_length=50)
       mail = models.CharField(max_length=50)
       name = models.CharField(max_length=50)
       phonenumber = models.IntegerField()def__str__(self):return"Website: {} Email: {} Name: {} Ph.: {}".format(self.website, self.mail, self.name, self.phonenumber)classMeta:
    
      db_table ="dreamreal"</code></pre>

    To propagate the new model in the database, run the makemigrations command −

    python manage.py makemigrations
    

    A migrations script 0001_initial.py will be created in the migrations folder. It contains a Migrations class. The migrate command as used initially, uses this script to create a new table in the database that has been configured in the DATABASES section of settings.py −

    Python manage.py migrate
    

    Eventually, you decide to add a new model class named Employee, as given below −

    classEmployee(models.Model):  
       eid = models.CharField(max_length=20)  
       ename = models.CharField(max_length=100)  
       eemail = models.EmailField()  
       econtact = models.CharField(max_length=15)classMeta:  
    
      db_table ="employee"</code></pre>

    When you run the makemigrations command again, it creates the second migration script −

    D:\workspace\myproject> python manage.py makemigrations myapp
    Migrations for'myapp':
       myapp\migrations\0002_employee.py
       - Create model Employee
    

    The new migration file 0002_employee.py is applied with migrate command −

    D:\workspace\myproject> python manage.py migrate              
    Operations to perform:
       Apply all migrations: admin, auth, contenttypes, myapp, sessions
    Running migrations:
       Applying myapp.0002_employee... OK
    

    If you check in the database structure, the employee table can be found in it.

    Django Update Model

    If you feel it necessary to change the structure of any of the models, you need to run the migrations again.

    We drop the email field and add the salary field.

    classEmployee(models.Model):  
       eid = models.CharField(max_length=20)  
       ename = models.CharField(max_length=100)    
       econtact = models.CharField(max_length=15)  
       salary = models.IntegerField()classMeta:  
    
      db_table ="employee"</code></pre>

    Run the makemigrations command again.

    D:\workspace\myproject> python manage.py makemigrations myapp 
    Migrations for'myapp':
       myapp\migrations\0003_remove_employee_eemail_employee_salary.py
    
      - Remove field eemail from employee
      - Add field salary to employee

    The showmigrations Command

    The showmigrations command shows the list of migrations scripts generated so far, with the migrations already applied showing "X" mark.

    python manage.py showmigrations
    myapp
       [X] 0001_initial
       [X] 0002_employee
       [] 0003_remove_employee_eemail_employee_salary
    

    Run the migrate command again to effect the changes to employee table −

    D:\workspace\myproject> python manage.py migrate
    Operations to perform:
       Apply all migrations: admin, auth, contenttypes, myapp, sessions
    Running migrations:
       Applying myapp.0003_remove_employee_eemail_employee_salary... OK
    

    How to Roll Back the Changes?

    If you want to roll back the recent changes to the employee table and restore the state of 0002_mployee.py script,

    D:\workspace\myproject> python manage.py migrate myapp 0002_employee
    Operations to perform:
       Target specific migration: 0002_employee,from myapp
    Running migrations:
       Rendering model states... DONE
       Unapplying myapp.0003_remove_employee_eemail_employee_salary... OK
    

    Go back and change the structure to confirm that the employee table structure is restored.

  • Update Data

    Django ORM uses the Active Record pattern for the interaction between a model class and its mapped database table. An instance of the model class corresponds to a single row in the table. Any of the attributes of the object results in updating the corresponding row.

    In this chapter, we will focus on the different ways available in Django to update an already existing row in a relational database.

    We shall use the Dreamreal model as given below for the exercise −

    classDreamreal(models.Model):
       website = models.CharField(max_length=50)
       mail = models.CharField(max_length=50)
       name = models.CharField(max_length=50)
       phonenumber = models.IntegerField()def__str__(self):return"Website: {} Email: {} Name: {} Ph.: {}".format(self.website, self.mail, self.name, self.phonenumber)

    It is assumed that you have already performed the migrations and added a few objects in the model.

    Update Object From Shell

    Django has a useful feature with which you can invoke a Python shell inside the Django project’s environment. Use the shell command with the manage.py script −

    python manage.py shell
    

    In front of the Python prompt, import the Dreamreal model −

    >>>from myapp.models import Dreamreal
    

    The model.objects attribute returns the model Manager, and its all() method returns a QuerySet. We can limit the objects in the set by applying the filter.

    To return the object with its primary key as 2, use the following statement −

    obj = Dreamreal.objects.filter(pk =2)

    The model class has the get() instance method with which we can change the value of one or more attributes.

    obj.update(f1=v1, f2=v2,...)

    Let us update the name of the object with “pk = 2” −

    obj.update(name='example')

    The model manager also has a get() method that fetches a single instance corresponding to the given keyword argument −

    obj = Dreamreal.objects.get(phonenumber =2376970)

    We can use a simple assignment to update an attribute. Let us change the phone number −

    obj.phonenumber =24642367570

    To make the change persistent, you need to call the save() method −

    obj.save()

    Perform Update Operation by Calling a View Function

    Let us now perform the update operation by calling a view function. Define the update() function in views.py file. This function receives the primary key as the argument from its mapped URL.

    from django.shortcuts import render
    from django.http import HttpResponse
    from myapp.models import Dreamreal
    
    defupdate(request, pk):
       obj = Dreamreal.objects.get(pk=pk)
       obj.name="admin"
       obj.save()return HttpResponse("Update successful")

    We also need to register this view in the urls.py file by adding a new path −

    from django.urls import path
    from.import views
    from.views import DRCreateView, update
    
    urlpatterns =[
       path("", views.index, name="index"),
       path("addnew/", views.addnew, name='addnew'),
       path("update/<int:pk>", views.update, name='update'),]

    Run the Django server and visit the URL http://localhost:8000/myapp/update/2. The browser emits the update success message.

    Instead of using the hard-coded values as in the above example, we would like the data to be accepted from the user. We need to populate a HTML form with the object data corresponding to the primary key.

    Modify the update() View Function

    Modify the update() view function as shown −

    from django.shortcuts import render
    from django.http import HttpResponse
    from myapp.models import Dreamreal
    
    defupdate(request, pk):
       obj = Dreamreal.objects.get(pk=pk)if request.method =="POST":
    
      ws = request.POST&#91;'website']
      mail = request.POST&#91;'mail']
      nm = request.POST&#91;'name']
      ph = request.POST&#91;'phonenumber']
      obj.name = nm
      obj.phonenumber = ph
      obj.save()return HttpResponse("&lt;h2&gt;Record updated Successfully&lt;/h2&gt;")
    obj = Dreamreal.objects.get(pk=pk) context ={"obj":obj}return render(request,"myform.html", context)

    We need to populate the form elements with the values of object attributes with the template variables.

    Modify the myform.html script as follows −

    <html><body><form action="../update/{{ obj.pk }}" method="post">
    
      {% csrf_token %}
      &lt;p&gt;&lt;label for="website"&gt;WebSite: &lt;/label&gt;&lt;input id="website" type="text" value = {{ obj.website }} name="website" readonly&gt;&lt;/p&gt;&lt;p&gt;&lt;label for="mail"&gt;Email: &lt;/label&gt;&lt;input id="mail" type="text" value = {{ obj.mail }} name="mail" readonly&gt;&lt;/p&gt;&lt;p&gt;&lt;label for="name"&gt;Name: &lt;/label&gt;&lt;input id="name" type="text" value = {{ obj.name }} name="name"&gt;&lt;/p&gt;&lt;p&gt;&lt;label for="phonenumber"&gt;Phone Number: &lt;/label&gt;&lt;input id="phonenumber" type="text" value = {{ obj.phonenumber }} name="phonenumber"&gt;&lt;/p&gt;&lt;input type="submit" value="Update"&gt;&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;</code></pre>

    Visiting the URL http://localhost:8000/myapp/update/2 renders a HTML form pre-populated with the data belonging to pk=2. User can update the name and phonenumber fields.

    Using ModelForm for Update

    Next, we shall use the ModelForm class to render a HTML form with its input elements corresponding to the model field types. Let use the DereamrealForm class that inherits the Modelform

    from django import forms
    from.models import Dreamreal
    
    classDreamrealForm(forms.ModelForm):classMeta:
    
      model = Dreamreal
      fields ="__all__"def__init__(self,*args,**kwargs):super(DreamrealForm, self).__init__(*args,**kwargs)
         self.fields&#91;'website'].widget = forms.TextInput(attrs={'readonly':'readonly'})
         self.fields&#91;'mail'].widget = forms.TextInput(attrs={'readonly':'readonly'})</code></pre>

    Note − Here, we have set the readonly property of the website and mail fields in the class constructor.

    The View function update() receives the primary key argument from the URL as before. When this function is called with POST method, the form data is used to update the existing object.

    When the GET method is used, Django fetches the object corresponding to the primary key, and uses its attributes to populate the HTML form −

    defupdate(request, pk):
       obj = Dreamreal.objects.get(pk=pk)if request.method =="POST":
    
      form = DreamrealForm(request.POST)if form.is_valid():
         form.save()return HttpResponse("&lt;h2&gt;Record updated Successfully&lt;/h2&gt;")
    obj = Dreamreal.objects.get(pk=pk) context ={"obj": DreamrealForm(instance=obj),"pk": obj.pk}return render(request,"myform.html", context)

    Visit the http://localhost:8000/myapp/update/1 URL to display the HTML form with its fields filled with the record with pk=1. You can change the values and submit for the corresponding object to be updated.

    Django Update Data

    The UpdateView Class

    Django defines a collection of generic view classes. The UpdateView class is specially designed for performing the INSERT query operation.

    We define a subclass of UpdateView class and set its template_name property to myform.html that we have already created.

    Add the following code in views.py file −

    from django.views.generic.edit import UpdateView 
    classDRUpdateView(UpdateView):  
       model = Dreamreal  
       fields ='__all__'  
       template_name ="myform.html"
       success_url ="../success/"

    To register this view, we need to update the urls.py file for our app. Note that, to register a generic view, we use the as_view() method.

    from django.urls import path
    from.import views
    from.views import DRCreateView, update, DRUpdateView
    
    urlpatterns =[
       path("", views.index, name="index"),
       path("addnew/", views.addnew, name='addnew'),
       path("add/", DRCreateView.as_view(), name='add'),
       path("success/", views.success, name='success'),
       path("update/<int:pk>", views.update, name='update'),
       path("updateview/<int:pk>", views.update, name='update'),]

    We need not change the myform.html script, as it renders the HTML script based on the respective model.

    Visit the updateview/1 URL to render the form pre-filled with the object having primary key = 1. Try and change one or more values and update the table.

  • Insert Data

    Django has its own Object Relation Model (ORM) that maps a Python class with a table in a relational database. The ORM mechanism helps in performing CRUD operations in object-oriented manner. In this chapter, we shall learn about different methods of inserting a new data.

    By default, Django uses a SQLite database. A model in Django is a class inherited from the “django.db.models” class.

    Let us use the following Dreamreal model in “models.py” file for learning how to insert data in the mapped table −

    from django.db import models
    
    classDreamreal(models.Model):
       website = models.CharField(max_length=50)
       mail = models.CharField(max_length=50)
       name = models.CharField(max_length=50)
       phonenumber = models.IntegerField()classMeta:
    
      db_table ="dreamreal"</code></pre>

    After declaring a model, we need to perform the migrations −

    python manage.py makemigrations
    python manage.py migrate
    

    Insert Object From Shell

    Django has a useful feature with which you can invoke a Python shell inside the Django project’s environment. Use the shell command with the manage.py script −

    python manage.py shell
    

    In front of the Python prompt, import the Dreamreal model −

    >>>from myapp.models import Dreamreal
    

    We can construct an object of this class and call its save() method so that the corresponding row is added in the table

    >>> obj = Dreamreal(website="www.polo.com", mail="[email protected]", name="sorex", phonenumber="002376970")>>> obj.save()

    We can confirm this by opening the database in any SQLite viewer.

    You can also use the create() method of the objects attribute of the model class to insert the record.

    >>> obj = Dreamreal.objects.create(website="www.polo.com", 
    mail="[email protected]", name="sorex", phonenumber="002376970")

    Perform Insert Operation by Calling a View Function

    Let us now perform the insert operation by calling a View function. Define addnew() function in views.py file as follows −

    from myapp.models import Dreamreal
    
    defaddnew(request):
       obj = Dreamreal(website="www.polo.com", mail="[email protected]", name="sorex", phonenumber="002376970")
       obj.save()return HttpResponse("<h2>Record Added Successfully")

    We need to register this View with the URLpatterns list.

    from django.urls import path
    from.import views
    
    urlpatterns =[
       path("", views.index, name="index"),
       path("addnew/", views.addnew, name='addnew')]

    Instead of using the hard-coded values as in the above example, we would like the data to be accepted from the user. For this purpose, create an HTML form in myform.html file.

    <html><body><form action="../addnew/" method="post">
    
      {% csrf_token %}
      &lt;p&gt;&lt;label for="website"&gt;WebSite: &lt;/label&gt;&lt;input id="website" type="text" name="website"&gt;&lt;/p&gt;&lt;p&gt;&lt;label for="mail"&gt;Email: &lt;/label&gt;&lt;input id="mail" type="text" name="mail"&gt;&lt;/p&gt;&lt;p&gt;&lt;label for="name"&gt;Name: &lt;/label&gt;&lt;input id="name" type="text" name="name"&gt;&lt;/p&gt;&lt;p&gt;&lt;label for="phonenumber"&gt;Phone Number: &lt;/label&gt;&lt;input id="phonenumber" type="text" name="phonenumber"&gt;&lt;/p&gt;&lt;input type="submit" value="OK"&gt;&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;</code></pre>

    The HTML template file must be stored in a directory defined in the TEMPLATES setting −

    TEMPLATES =[{'BACKEND':'django.template.backends.django.DjangoTemplates','DIRS':[BASE_DIR/'templates'],....,]

    Let us use the render() function to display the form template −

    from django.shortcuts import render
    from myapp.models import Dreamreal
    
    defaddnew(request):if request.method =="POST":
    
      ws = request.POST&#91;'website']
      mail = request.POST&#91;'mail']
      nm = request.POST&#91;'name']
      ph = request.POST&#91;'phonenumber']
      obj = Dreamreal(website=ws, mail=mail, name=nm, phonenumber=ph)
      obj.save()return HttpResponse("&lt;h2&gt;Record Added Successfully&lt;/h2&gt;")return render(request,"myform.html")</code></pre>

    Note that the form’s action attribute is also set to the same URL mapping the addnew() function. Hence, we need to check the request.method. If it’s GET method, the blank form is rendered. If it’s POST method, the form data is parsed and used for inserting a new record.

    Django Insert Data 1

    The Model Form

    Django has a ModelForm class that automatically renders a HTML form with its structure matching with the attributes of a model class.

    We define a DreamRealForm class in forms.py file under the app folder that uses the Dreamreal model as the basis.

    from django import forms
    from.models import Dreamreal
    
    classDreamrealForm(forms.ModelForm):classMeta:
    
      model = Dreamreal
      fields ="__all__"</code></pre>

    An object of the model form is rendered on the HTML form. In case the request method is POST, the save() method of the ModelForm class automatically validates the form and saves a new record.

    from.forms import DreamrealForm
    defaddnew(request):if request.method =='POST':
    
      form = DreamrealForm(request.POST)if form.is_valid():
         form.save()return HttpResponse("&lt;h2&gt;Book added successfully&lt;/h2&gt;")
    context={'form': DreamrealForm}return render(request,"myform.html", context)
    Django Insert Data 2

    The CreateView Class

    Django defines a collection of generic view classes. The CreateView class is specially designed for performing the INSERT query operation.

    We define a subclass of CreateView class and set its template_name property to myform.html that we have already created.

    Add the following code in views.py file −

    from django.views.generic import CreateView
    classDRCreateView(CreateView):
       model = Dreamreal
       fields ="__all__"
       template_name ='myform.html'
       success_url ='../success/'

    On successful insertion, the browser is redirected to the success() view function.

    defsuccess(request):return HttpResponse("<h2>Book added successfully</h2>")

    Both the above views must be included in the URL pattern list of urls.py file. The generic view classes are registered with their as_view() method.

    from django.urls import path
    from.import views
    from.views import DRCreateView
    
    urlpatterns =[
       path("", views.index, name="index"),
       path("addnew/", views.addnew, name='addnew'),
       path("add/", DRCreateView.as_view(), name='add'),
       path("success/", views.success, name='success'),]

    In this chapter, we learned the different ways to insert data in a Django model.

  • Models

    A model is a class that represents table or collection in our DB, and where every attribute of the class is a field of the table or collection. Models are defined in the app/models.py (in our example: myapp/models.py)

    Creating a Model

    Following is a Dreamreal model created as an example −

    from django.db import models
    
    class Dreamreal(models.Model):
    
       website = models.CharField(max_length = 50)
       mail = models.CharField(max_length = 50)
       name = models.CharField(max_length = 50)
       phonenumber = models.IntegerField()
    
       class Meta:
    
      db_table = "dreamreal"</code></pre>

    Every model inherits from django.db.models.Model.

    Our class has 4 attributes (3 CharField and 1 Integer), those will be the table fields.

    The Meta class with the db_table attribute lets us define the actual table or collection name. Django names the table or collection automatically: myapp_modelName. This class will let you force the name of the table to what you like.

    After creating your model, you will need Django to generate the actual database −

    $python manage.py syncdb
    

    Manipulating Data (CRUD)

    Let's create a "crudops" view to see how we can do CRUD operations on models. Our myapp/views.py will then look like −

    myapp/views.py

    from myapp.models import Dreamreal
    from django.http import HttpResponse
    
    def crudops(request):
       #Creating an entry
       
       dreamreal = Dreamreal(
    
      website = "www.polo.com", mail = "[email protected]", 
      name = "sorex", phonenumber = "002376970"
    ) dreamreal.save() #Read ALL entries objects = Dreamreal.objects.all() res ='Printing all Dreamreal entries in the DB : <br>' for elt in objects:
      res += elt.name+"&lt;br&gt;"
    #Read a specific entry: sorex = Dreamreal.objects.get(name = "sorex") res += 'Printing One entry <br>' res += sorex.name #Delete an entry res += '<br> Deleting an entry <br>' sorex.delete() #Update dreamreal = Dreamreal(
      website = "www.polo.com", mail = "[email protected]", 
      name = "sorex", phonenumber = "002376970"
    ) dreamreal.save() res += 'Updating entry<br>' dreamreal = Dreamreal.objects.get(name = 'sorex') dreamreal.name = 'thierry' dreamreal.save() return HttpResponse(res)

    Other Data Manipulation

    Let's explore other manipulations we can do on Models. Note that the CRUD operations were done on instances of our model, now we will be working directly with the class representing our model.

    Let's create a 'datamanipulation' view in myapp/views.py

    from myapp.models import Dreamreal
    from django.http import HttpResponse
    
    def datamanipulation(request):
       res = ''
       
       #Filtering data:
       qs = Dreamreal.objects.filter(name = "paul")
       res += "Found : %s results<br>"%len(qs)
       
       #Ordering results
       qs = Dreamreal.objects.order_by("name")
       
       for elt in qs:
    
      res += elt.name + '&lt;br&gt;'
    return HttpResponse(res)

    Linking Models

    Django ORM offers 3 ways to link models −

    One of the first case we will see here is the one-to-many relationships. As you can see in the above example, Dreamreal company can have multiple online websites. Defining that relation is done by using django.db.models.ForeignKey −

    myapp/models.py

    from django.db import models
    
    class Dreamreal(models.Model):
       website = models.CharField(max_length = 50)
       mail = models.CharField(max_length = 50)
       name = models.CharField(max_length = 50)
       phonenumber = models.IntegerField()
       online = models.ForeignKey('Online', default = 1)
       
       class Meta:
    
      db_table = "dreamreal"
    class Online(models.Model):
      domain = models.CharField(max_length = 30)
    class Meta:
      db_table = "online"</code></pre>

    As you can see in our updated myapp/models.py, we added the online model and linked it to our Dreamreal model.

    Let's check how all of this is working via manage.py shell −

    First let’s create some companies (Dreamreal entries) for testing in our Django shell −

    $python manage.py shell
    
    >>> from myapp.models import Dreamreal, Online
    >>> dr1 = Dreamreal()
    >>> dr1.website = 'company1.com'
    >>> dr1.name = 'company1'
    >>> dr1.mail = 'contact@company1'
    >>> dr1.phonenumber = '12345'
    >>> dr1.save()
    >>> dr2 = Dreamreal()
    >>> dr1.website = 'company2.com'
    >>> dr2.website = 'company2.com'
    >>> dr2.name = 'company2'
    >>> dr2.mail = 'contact@company2'
    >>> dr2.phonenumber = '56789'
    >>> dr2.save()

    Now some hosted domains −

    >>> on1 = Online()
    >>> on1.company = dr1
    >>> on1.domain = "site1.com"
    >>> on2 = Online()
    >>> on2.company = dr1
    >>> on2.domain = "site2.com"
    >>> on3 = Online()
    >>> on3.domain = "site3.com"
    >>> dr2 = Dreamreal.objects.all()[2]
    >>> on3.company = dr2
    >>> on1.save()
    >>> on2.save()
    >>> on3.save()

    Accessing attribute of the hosting company (Dreamreal entry) from an online domain is simple −

    >>> on1.company.name
    

    And if we want to know all the online domain hosted by a Company in Dreamreal we will use the code −

    >>> dr1.online_set.all()
    

    To get a QuerySet, note that all manipulating method we have seen before (filter, all, exclude, order_by....)

    You can also access the linked model attributes for filtering operations, let's say you want to get all online domains where the Dreamreal name contains 'company' −

    >>> Online.objects.filter(company__name__contains = 'company'
    

    Note − That kind of query is just supported for SQL DB. It won’t work for non-relational DB where joins doesn’t exist and there are two '_'.

    But that's not the only way to link models, you also have OneToOneField, a link that guarantees that the relation between two objects is unique. If we used the OneToOneField in our example above, that would mean for every Dreamreal entry only one Online entry is possible and in the other way to.

    And the last one, the ManyToManyField for (n-n) relation between tables. Note, those are relevant for SQL based DB.