How to relate a model to another model in Django 2

Asked

Viewed 828 times

0

I’m making a system in which I need to show data that is registered in another Model, which in this case is the Category field that is in the Model Items and when showing it, the user would select one of them and the system would show the data that are only linked to the selected category.

Ex.:

Locker register

Name:

Description:

Categories: Footwear| Pants| Blouses| * I selected Blouses

Items: Here the system shows only items in the Blouses category with the option to select the item

Locker: Will contain the selected items.


models.py items

from django.db import models

class Categoria(models.Model):
    name_categoria = models.CharField(max_length=100, null=True)

    def __str__(self):
        return self.name_categoria

class Cor(models.Model):
    cor_item = models.CharField(max_length=50, null=True)

    def __str__(self):
        return self.cor_item

class ItenManager(models.Manager):
    def search(self, query):
        return self.get_queryset().filter(
            models.Q(name__icontains=query) | \
            models.Q(cor__icontains=query)
        )

class Itens(models.Model):
    name = models.CharField('Nome:', max_length=100)
    slug = models.SlugField('Atalho:')
    categoria = models.ForeignKey('Categoria',on_delete=models.CASCADE)
    cor = models.ForeignKey('Cor', on_delete=models.CASCADE)
    image = models.ImageField(
        upload_to='itens_imagens', verbose_name='Imagem:', null=True, blank=True
    )
    objects = ItenManager()

    def __str__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('itens:details', (), {'slug': self.slug})

    class Meta:
        verbose_name = 'Item'
        verbose_name_plural = 'Itens'
        ordering = ['name']

cabinet models.py

from django.db import models

class Armario(models.Model):
    name= models.CharField('Nome',max_length=50, blank=False)
    slug = models.SlugField('Atalho')
    descricao = models.CharField('Descrição',max_length=100, blank=True)
    created_at = models.DateField('Criado em', auto_now_add=True)
    updated_at = models.DateField('Atualizado em',auto_now=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Armário'
        verbose_name_plural = 'Armários'
        ordering = ['name']
  • You can use javascript (ajax) to send a request to the Django url when the user selects the category.

1 answer

1

Well, the relationship between the models is already done there - there’s not much to work with on this side.

Now is to think how you will present this information. If you are developing a WEB application with static pages: your views return rendered templates, which are filled with Python variables, the only thing you need the most (besides thinking about your views and templates), is to put the option related_name on the model Itens. (by the way, 'items' may not be a good name - if you do not find anything better, at least it is better to leave in the singular Item - all other classes are in the singular, it is not?)

But then, within items, you declare the categories like this:

categoria = models.ForeignKey('Categoria', related_name='itens', on_delete=models.CASCADE)

Doing this, inside class objects Categoria you can use the attribute itens that returns a sequence of all items in that category - this can be used directly in the template, with the for:

<p> Categoria {{ categoria.name_categoria }} :<p>
<ul>
  {% for item in categoria.items %}
    <li>{{ item.name }}</li>
  {% endfor %}
</ul>

This works because when Django preenceh a template’s data, it is still done by Python code running on the server, which has access to all variables and the database.

Now, if your application loads data dynamically, with ajax, or using frameworks like angular, React, etc.. - in this case you will get views that return data from serialized objects like JSON.

In this case, to save calls, it might be interesting to embed some of the data from your items when the person requests a category - this can be done manually in the view code (you create a Python dictionary that will add all the data that will be passed to the front-end, in this dictionary includes a key itens, and a list of the names and links to the items, for example),

from Django.http import Jsonresponse

def categorias_view(request):
    resposta = []
    for categoria in models.Categoria.objects.all():
        dados_categoria = {}
        dados_categoria['nome'] = categoria.categoria_name
        dados_categoria['itens'] = [item.name for item in categoria.items]
        resposta.append(dados_categoria)
    return JsonResponse(resposta)

The other option in the case of a web app with dynamic calls, is to take one more step and see about the "Django Rest framework" (DRF) - which allows you to use very little or no code to process these views that render the data of objects like JSON. In this case, you will create classes associated with each template that are called "serializers". The framework gives a lot of shortcuts for you to embed the desired related data within your JSON without having to do it manually.
The use of DRF does a lot of magic, which can save a lot of typing on large systems - but if you have a few objects, and you’re learning, I would recommend doing the views by manually returning json, until you understand what you’re doing, and what you’d like to automate, and then move on to the DRF - otherwise it will look like a lot of extra bureaucracy, and in the end it does a magic and "it works".

Browser other questions tagged

You are not signed in. Login or sign up in order to post.