DEV Community

ilija
ilija

Posted on • Updated on

Web3 backend and smart contract development for Python developers Musical NFTs part 12: NFT cards in user profile

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}")
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}) 

Enter fullscreen mode Exit fullscreen mode

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%}

Enter fullscreen mode Exit fullscreen mode

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

Github code

Top comments (0)