Set the user logged in to model | Django + Python3 as default
I'm trying to learn Django, and with that I'm trying to create a simple ticket system.
I have advanced a lot in my studies, but now I have packed into the following problem.
How does Django save the currently logged in user by default when saving a Ticket?
Follow my file codes models.py
from django.contrib.auth.models import User
from django.db import models
from datetime import datetime
class Projeto(models.Model):
"""
Classe que gere os Projetos
Permite que se cadastre N usuários por Projeto
Retorna:
NOME_DO_PROJETO | SITE_DO_PROJETO
"""
nome = models.CharField(max_length=100)
site = models.CharField(max_length=200)
informacoes = models.TextField(blank=True)
usuarios = models.ManyToManyField(User, related_name='projetos')
def __str__(self):
return self.nome + " | " + self.site
class Ticket(models.Model):
"""
Classe que gere os Tickets no sistema.
Retorna:
DATA HORA | TITULO DO CHAMADO
"""
TIPOS_TICKET = (
('BUG', 'Bug'),
('URGENTE', 'Urgente'),
('FINANCEIRO', 'Financeiro'),
('MELHORIA', 'Melhoria')
)
STATUS_TICKET = (
('ABERTO', 'Aberto'),
('AGUARDANDO_CLIENTE', 'Aguardando Cliente'),
('EM_ANALISE', 'Em Análise'),
('FINALIZADO', 'Finalizado'),
('CANCELADO', 'Cancelado'),
)
titulo = models.CharField(max_length=200)
conteudo = models.TextField()
tipo = models.CharField(max_length=30, choices=TIPOS_TICKET, default='BUG')
status = models.CharField(max_length=30, choices=STATUS_TICKET, default='ABERTO')
projeto = models.ForeignKey(
Projeto,
on_delete=models.CASCADE,
limit_choices_to={'usuarios':1}
)
usuario = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True
)
data_abertura = models.DateTimeField('Data Abertura', auto_now_add=True)
data_fechamento = models.DateTimeField('Data Fechamento', blank=True, null=True)
def __str__(self):
return str(datetime.strftime(self.data_abertura, "%d/%m/%y %H:%M") + " | " + self.titulo)
def save(self, *args, **kwargs):
self.usuario = User
super(Ticket, self).save(*args, **kwargs)
class TicketMsg(models.Model):
"""
Mensagens dos tickets
Retorna:
texto da mensagem
"""
texto = models.TextField()
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
data_resposta = models.DateTimeField('Data Resposta')
def __str__(self):
return str(self.texto)
And my file admin.py
from django.contrib import admin
from django.contrib.auth.models import User
from .models import Ticket, TicketMsg, Projeto
# Register your models here.
class ProjetoAdmin(admin.ModelAdmin):
model = Projeto
filter_horizontal = ('usuarios',)
class TicketAdmin(admin.ModelAdmin):
model = Ticket
exclude = ('status', 'data_fechamento', 'data_abertura', 'usuario')
list_display = ('titulo', 'tipo', 'status', 'projeto', 'data_abertura')
list_filter = ('projeto', 'tipo', 'status')
def get_ordering(self, request):
return ['data_abertura']
admin.site.register(Projeto, ProjetoAdmin)
admin.site.register(Ticket, TicketAdmin)
admin.site.register(TicketMsg)
This is the result so far of the listing, using the Django
The idea is that when the person enters a ticket, the system identifies which user did it.
I have already managed to make the system filter which projects a user has the right to open ticket for.
Now the system fails to record the ID of the logged in user so that I can identify who opened the ticket.
Follows form image:
All help is welcome! Thank you guys!
2 answers
There is a method called .save_model
in ModelAdmin that aims to do pre and post save operations.
class TicketAdmin(admin.ModelAdmin):
...
def save_model(self, request, obj, form, change):
obj.user = request.user
super(ArticleAdmin, self).save_model(request, obj, form, change)
More details in the documentation ModelAdmin.save_model .
Another solution that I typically use is to create an "abstract" class, which implements the typical logic of writing the user who created the record or who updated the record, but here adapted to your case:
For your example, you create a file common.py:
Common.py
from django.conf import settings
from django.db import models
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from ai.middleware.current_user import CurrentUserMiddleware
from django.contrib.admin.models import LogEntry
from django.contrib.contenttypes.fields import GenericRelation
class CommonInfo(models.Model):
usuario = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_("Usuário"), blank=True, null=True,
related_name="%(app_label)s_%(class)s_created", on_delete=models.SET_NULL, editable=False)
@staticmethod
def get_current_user():
"""
Get the currently logged in user over middleware.
Can be overwritten to use e.g. other middleware or additional functionality.
:return: user instance
"""
return CurrentUserMiddleware.get_current_user()
def set_user_fields(self, user):
"""
Set user-related fields before saving the instance.
If no user with primary key is given the fields are not set.
:param user: user instance of current user
"""
if user and user.pk:
if not self.pk:
self.usuario = user
else:
self.usuario = user
def save(self, *args, **kwargs):
current_user = self.get_current_user()
self.set_user_fields(current_user)
super(CommonInfo, self).save(*args, **kwargs)
class Meta:
abstract = True
In your models you change to use the abstract class:
Models.py
from yourapp.common import CommonInfo
class Ticket(CommonInfo): # trocas models.Model por CommonInfo, que já herda de models.Model
"""
Classe que gere os Tickets no sistema.
Retorna:
DATA HORA | TITULO DO CHAMADO
"""
TIPOS_TICKET = (
('BUG', 'Bug'),
('URGENTE', 'Urgente'),
('FINANCEIRO', 'Financeiro'),
('MELHORIA', 'Melhoria')
)
STATUS_TICKET = (
('ABERTO', 'Aberto'),
('AGUARDANDO_CLIENTE', 'Aguardando Cliente'),
('EM_ANALISE', 'Em Análise'),
('FINALIZADO', 'Finalizado'),
('CANCELADO', 'Cancelado'),
)
titulo = models.CharField(max_length=200)
conteudo = models.TextField()
tipo = models.CharField(max_length=30, choices=TIPOS_TICKET, default='BUG')
status = models.CharField(max_length=30, choices=STATUS_TICKET, default='ABERTO')
projeto = models.ForeignKey(
Projeto,
on_delete=models.CASCADE,
limit_choices_to={'usuarios':1}
)
# usuario = models.ForeignKey(User, on_delete=models.CASCADE, null=True) # removes esta linha, uma vez que herda da classe CommonInfo
data_abertura = models.DateTimeField('Data Abertura', auto_now_add=True)
data_fechamento = models.DateTimeField('Data Fechamento', blank=True, null=True)
def __str__(self):
return str(datetime.strftime(self.data_abertura, "%d/%m/%y %H:%M") + " | " + self.titulo)
def save(self, *args, **kwargs):
# self.usuario = User deixa de ser necessário esta linha uma vez que já grava na classe abstract
super(Ticket, self).save(*args, **kwargs)