Web3 backend and smart contract development for Python developers Musical NFTs part 12: NFT cards in user profile
Tags: python, django, ethereum, nft
Published: 2023-10-14 16:04:27

In this part we will try to show inside user profile all musical NFTs user own as set of cards. For this to happen we will need one more model `NFTmetadata`. In this model we will add basic informations about existing NFTs (name, description etc.). Inside our already existing file `authentication/models.py` we should add following code    

```
from django.contrib.postgres.fields import ArrayField
from django.db import models


    class NFTMetadata(models.Model):
        name = models.CharField(max_length=100)
        description = models.CharField(max_length=2000)
        cover_file_name = models.CharField(max_length=50)

        def __str__(self):
            return (f"{self.name}")

    class Customer(models.Model):
        
        CRYPTO = "CRYPTO"
        CREDIT = "CREDIT"

        OPTIONS = [
            (CRYPTO, "cypto buyer"),
            (CREDIT, "credit card buyer")
        ]
        
        created_at = models.DateTimeField(auto_now=True)
        first_name = models.CharField(max_length=50, blank=True)
        last_name  = models.CharField(max_length=50, blank=True)
        username = models.CharField(max_length=50, blank=True) 
        email = models.EmailField(max_length=250, blank=True)
        type = models.CharField( 
            max_length = 20, 
            choices = OPTIONS, 
            # default="CRYPTO"
            ) 
        total_no_of_nfts = models.IntegerField(default=0)
        nft_ids = ArrayField(models.IntegerField(null=True, blank=True), null=True, blank=True) 
        nft_metadata_ids = ArrayField(models.IntegerField(null=True, blank=True), null=True, blank=True) 
        nft_metadata = models.ManyToManyField(NFTMetadata)

        def __str__(self):
            return (f"{self.first_name} {self.last_name}")
```

Now in `models.py` we have two new things. First is `NFTMetadata` class which will be used to create different `NFTMetadata` entries in database. We need this information when we show to user which NFTs he own. Inside our old `Customer` class we added one many-to-many filed which will allow us to connect this new `NFTMetadata` entries with individual `Customer`. 

Now for test purpose we will go to Django console and add few `NFTMetadata` entries by hand. Just to have some informations to show on front-end. In the same time this is good opportunity for us to demonstrate how powerful can be `Django shell` in this development phase. 

Inside bash terminal project root directory:

    $python managa.py shell

    Python 3.8.10 (default, May 26 2023, 14:05:08) 
    Type 'copyright', 'credits' or 'license' for more information
    IPython 8.11.0 -- An enhanced Interactive Python. Type '?' for help.

    In [1]: user = Customer.objects.get(username="denis")

Now inside this shell we can work with our models, create them, update, delete and all other things we can do in normal Python class inside `views.py`

    In [1]: from authentication.models import Customer, NFTMetadata
    
    # Here we are grabing user from our database
    In [2]: user = Customer(username="denis")
    
    # Now we create few entries for NFTMetadata class
    In [3]: nft1 = NFTMetadata(name="Gang of four", description="British post-punk band", cover_file_name="gang_of_four.jpg")
    In [4]: nft2 = NFTMetadata(name="Kesih Jones", description="Nigerian singer-songwriter and guitarist.", cover_file_name="kezih_jones.jpg")
    In [5]: nft3 = NFTMetadata(name="Cesaria Evora", description="Cesaria Evora, Cape Verdean singer who was known for her rich, haunting voice", cover_file_name="cesaria_evora.jpg")

    # Now we need to save our entris in database
    In [5] nft1.save()
    In [6] nft2.save()
    In [7] nft3.save()


    # With this we have 3 new entris

    # Now we will asigne this three instancies to our denis customer (later to be shown inside his persaonl profile) 

    In [8] user.nft_metadata.add(nft1, nft2, nft3)

    # With this we associate this 3 NFTs metadata to denis user (for test 
    # purpose only to be shown in his user profile page)

    # if we want to check if everything whent well we can type
    In [8] metadata = user.nft_metadata.all()
    In [9] for x in metadata:
            print(x)
    
        Gang of four
        Kesih Jones
        Cesaria Evora

Ok, now denis user have 3 NFTs associated with his account. Here is important to point out that later on `nft_metadata` will be filled automaticaly when user buy new NFT. For now we will do that by hand.

What we need in this moment is to show data as a cards every time user login into his account. For this to happen we will need to render information's about NFTs he own to the front-end. If you can recall we already have customer date of logged in user assigned to variable user inside our `HomeView` class. And then in second step from user we will extract all nft_metadata instancies assigned to this profile. What means our `views.py` will mainly stay the same except few minor adjustments. Here is new code with inline comments (look at get method)

    

```
class HomeView(TemplateView):

        def post(self, request):
                if "username" in request.POST:
                    # check to see if loggin in
                    user_name = request.POST["username"]
                    password = request.POST["password"]
                    user = authenticate(request, username=user_name, password=password)
                    if user is not None:
                        login(request, user)
                        messages.success(request, "You have been logged in!")
                        return redirect("home")    
                    else:
                        messages.success(request, "There was An Error login in, please try again")
                        return redirect("home")  
                else:
                    user = Customer.objects.get(username=request.user)                
                    form = OrderForm(instance=user, data=request.POST)
                    if form.is_valid():
                        form.save()
                        messages.success(request, "You successfully update payment method")
                        return redirect("home")
                    messages.success(request, "There was an error in updating of your payment method")
                    return redirect("home")
            
        def get(self, request):
            if str(request.user) == "AnonymousUser":
                return render(request, "home.html", {})
            name = str(request.user)
            customer = Customer.objects.get(username=name)
            # This is new part of code. Here we pull all instancies of 
            # NFTMetadata class and pass as new contex varibale inside 
            # `metadata` key
            nft_metadata = customer.nft_metadata.all()
            form = OrderForm()
            return render(request, "home.html", {"customer": customer, "form": form, "metadata": nft_metadata})

    class LogoutUser(TemplateView):    
        def get(self, request):
            logout(request)
            messages.success(request, "You have been logged out!")
            return redirect("home")  

class RegisterUser(TemplateView):
    
    def post(self, request): 
        # Everything what user send pass to our SignUpForm
        form = SignUpForm(request.POST)
        if form.is_valid():
            form.save()

            # Authenticate use and login
            username = form.cleaned_data['username']
            password = form.cleaned_data['password1']
            user = authenticate(username=username, password=password)
            login(request, user)
            Customer.objects.create(username=user, email=user.email, first_name=user.first_name, last_name=user.last_name)
            messages.success(request,  "You have been sucesfuly logged in ")
            return redirect("home")
        return render(request, "register.html", {"form": form}) 

    def get(self, request):
        form = SignUpForm()
        return render(request, "register.html", {"form": form}) 

```




What we need to do now is to loop over this value from contex we pass iniside our `home.html` template card and to list all things user have inside his user profile. In attempt for all this to work we will need to add one more  thing inside  `home.html`, namely one for loop. Here is how our `home.html` file should look like now (later on we will celan up a bit this file)


    

```
{% extends "base.html" %}
    {% block content%}
    {% if user.is_authenticated %}
        {% if customer.type == "CRYPTO"%}
        <table class="table  table-hover">
        <thead class="table-dark">
            <tr>
            <th scope="col">Name</th>
            <th scope="col">Email</th>
            <th scope="col">Total no. NFTs</th>
            <th scope="col">Means of payment</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td> {{ customer.first_name }} {{ customer.last_name }} </td>
                <td> {{ customer.email }} </td>
                <td> {{ customer.total_no_of_nfts }} </td>
                <td><form action="" method="post">
                {%csrf_token%}
                {{form.as_p}}
                <input type="submit" value="Save" class="btn btn-secondary">
            </form>
                </td>         
            </tr>
            </tbody>
        </table>      
        {% for card in metadata%}
        {% if forloop.counter0|divisibleby:3 %} <div class="row">{%  endif %}
            <div class="card m-5 p-2" style="width: 18rem;">
            {% load static %}
            <img src="{% static 'nft/'%}{{card.cover_file_name}}"  class="card-img-top" alt="..." width="50" height="200"/>
            <div class="card-body">
                <h5 class="card-title">{{card.name}}</h5>
                <br>
                <p class="card-text">{{card.description}}</p>
            </div>
            </div>
        {%  if forloop.counter|divisibleby:3 or forloop.last %}</div> {%  endif %}
        <br>
        {% endfor %}
        {% else %}
        <table class="table  table-hover">
            <thead class="table-dark">
            <tr>
                <th scope="col">Name</th>
                <th scope="col">Email</th>
                <th scope="col">Total no. NFTs</th>
                <th scope="col">Means of payment</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td> {{ customer.first_name }} {{ customer.last_name }} </td>
                <td> {{ customer.email }} </td>
                <td> {{ customer.total_no_of_nfts }} </td>
                <td><form action="" method="post">
                    {%csrf_token%}
                    {{form.as_p}}
                    <input type="submit" value="Save" class="btn btn-secondary">
                </form>
                </td>         
                </tr>
            </tbody>
            </table>        
            {% for card in metadata%}
            {% if forloop.counter0|divisibleby:3 %} <div class="row">{%  endif %}
            <div class="card m-5 p-2" style="width: 18rem;">
                {% load static %}
                <img src="{% static 'nft/'%}{{card.cover_file_name}}"  class="card-img-top" alt="..." width="50" height="200"/>
                <div class="card-body">
                <h5 class="card-title">{{card.name}}</h5>
                <br>
                <p class="card-text">{{card.description}}</p>
                </div>
            </div>
            {%  if forloop.counter|divisibleby:3 or forloop.last %}</div> {%  endif %}
            <br>
            {% endfor %}
            <p> credit card </p>
        {% endif %}
        {% else %}
        <div class="col-md-6 offset-md-3"> 
        <h1> Login </h1>
        <br/>
        <form method="POST" action="{% url 'home' %}"> 
            {% csrf_token %}        
                <div class="mb-3">
                <input type="text" class="form-control" aria-describedby="emailHelp" placeholder="Username" name="username" required>
                </div>
                <div class="mb-3">
                <input type="password" class="form-control" placeholder="Password" name="password" required>
                </div>
                <button type="submit" class="btn btn-secondary">Login</button>
            </form> 
        </div>
    {% endif %}
    {% endblock content%}

```

As you can see above `{% load static %}` we added one for loop to loop over all NFT metadata user have. Ones we pick up first entry we will fill in our card and go to next till the end. Now if you run your Django server and go to browser on `http://127.0.0.1:8000` you should see something like this


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/is9v32tc0rnpmve1bnd6.png)


 Github [code](https://github.com/ilijapet/musical_nft_thumbnails)