How to relate a model to another model in Django 2

0

I'm doing 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 Model Items and in showing them, the user would select one of them and the system would show the data that are only linked to the selected category.

Ex:

Cabinet Registration

Name:

Description:

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

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

Cabinet: Contains the selected items.

items \ models.py

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']
    
asked by anonymous 13.11.2018 / 08:25

1 answer

1

Well, the relationship between the models is already done there - there is not much to deal with on that 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 populated with Python variables, the only thing you need the most (besides thinking well about your views and templates), is to set the related_name option % in model Itens . (in fact, 'items' might not be a good name - if you do not find anything better, at least it's best to leave the singular Item - all other classes are in the singular, is not it?)

But then, inside items, you declare categories like this:

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

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

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

This works because when django precedes the data in a template, 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 that case you will have views that return the data of serialized objects like JSON.

In this case, to save calls, it may be interesting to embed some of your item data when a person requests a category - this can be done manually in the view code (you create a Python dictionary that will add all the data you will be passed to the front-end, in that dictionary it includes a itens key, and a list with 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 another step and look at the "Django rest framework" (DRF) - which allows you to use little or no code to generate those views that render the data of the objects as JSON. In this case, you will create classes associated with each model that are called "serializers" . The framework gives a number of shortcuts for you to embed the desired related data within your JSON without having to do this manually.
Using DRF does a lot of magic, which can save a lot of typing on large systems - but if you have few objects, and are learning, I would recommend doing the json returning views manually, until you understand what you are doing, and what you would give to automate, and then move on to the DRF - otherwise it will look like a lot of bureaucracy the most, and in the end it does a magic and "works."

    
13.11.2018 / 12:06