
from django.contrib.admin.models import LogEntry, CHANGE >>>> 2.
from django.contrib.contenttypes.models import ContentType >>>>> 2.
def refund(modeladmin, request, queryset):
with transaction.atomic():
qs = queryset.filter(~Q(status='ํ๋ถ'))
ct = ContentType.objects.get_for_model(queryset.model)
for obj in qs:
obj.product.stock += obj.quantity
obj.product.save()
LogEntry.objects.log_action( >>>>> 3.
user_id = request.user.id,
content_type_id=ct.pk,
object_id=obj.pk,
object_repr='์ฃผ๋ฌธ ํ๋ถ',
action_flag=CHANGE,
change_message='์ฃผ๋ฌธ ํ๋ถ'
)
qs.update(status='ํ๋ถ')
์ฅ๊ณ ์ด๋๋ฏผ ํ์ด์ง์ ๋ชจ๋ธ์ ๋ณ๊ฒฝํ๋ฉด ๊ธฐ๋ก์ด ๋จ๋๋ฐ ์ด ๋ถ๋ถ์ ์ปค์คํฐ๋ง์ด์ง์ ํ๋ค.
์คํํ๊ธฐ ์ํด์ ์๋ ๊ฒ๋ค์ ์ํฌํธ ํ๋ค.
from django.contrib.admin.models import LogEntry, CHANGEfrom django.contrib.contenttypes.models import ContentType๊ธฐ์กด์ ๊ตฌํํด ๋์ ๋ฐ๋ณต๋ฌธ์ Logentry๊ฐ์ฒด์ ์ ๊ทผํด์ ๊ฐ๋ค์ ๋ฐ๊พธ์ด์ค๋ค.
class LogEntry(models.Model):
action_time = models.DateTimeField(
_('action time'),
default=timezone.now,
editable=False,
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
models.CASCADE,
verbose_name=_('user'),
)
content_type = models.ForeignKey(
ContentType,
models.SET_NULL,
verbose_name=_('content type'),
blank=True, null=True,
)
object_id = models.TextField(_('object id'), blank=True, null=True)
# Translators: 'repr' means representation (https://docs.python.org/library/functions.html#repr)
object_repr = models.CharField(_('object repr'), max_length=200)
action_flag = models.PositiveSmallIntegerField(_('action flag'), choices=ACTION_FLAG_CHOICES)
# change_message is either a string or a JSON structure
change_message = models.TextField(_('change message'), blank=True)
objects = LogEntryManager() >>>>>>>>>>>>>>>>>>>>>>>>>
class LogEntryManager(models.Manager):
use_in_migrations = True
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
if isinstance(change_message, list):
change_message = json.dumps(change_message)
return self.model.objects.create(
user_id=user_id,
content_type_id=content_type_id,
object_id=str(object_id),
object_repr=object_repr[:200],
action_flag=action_flag,
change_message=change_message,
)
from django.contrib.admin.models import LogEntry, CHANGE >>>> 2.
from django.contrib.contenttypes.models import ContentType >>>>> 2.
def refund(modeladmin, request, queryset):
with transaction.atomic():
qs = queryset.filter(~Q(status='ํ๋ถ'))
ct = ContentType.objects.get_for_model(queryset.model) >>>> 4.
for obj in qs:
obj.product.stock += obj.quantity
obj.product.save()
LogEntry.objects.log_action( >>>>> 3.
user_id = request.user.id,
content_type_id=ct.pk,
object_id=obj.pk,
object_repr='์ฃผ๋ฌธ ํ๋ถ',
action_flag=CHANGE,
change_message='์ฃผ๋ฌธ ํ๋ถ'
)
qs.update(status='ํ๋ถ')
def get_for_model(self, model, for_concrete_model=True):
"""
Return the ContentType object for a given model, creating the
ContentType if necessary. Lookups are cached so that subsequent lookups
for the same model don't hit the database.
"""
opts = self._get_opts(model, for_concrete_model)
try:
return self._get_from_cache(opts)
except KeyError:
pass
# The ContentType entry was not found in the cache, therefore we
# proceed to load or create it.
try:
# Start with get() and not get_or_create() in order to use
# the db_for_read (see #20401).
ct = self.get(app_label=opts.app_label, model=opts.model_name)
except self.model.DoesNotExist:
# Not found in the database; we proceed to create it. This time
# use get_or_create to take care of any race conditions.
ct, created = self.get_or_create(
app_label=opts.app_label,
model=opts.model_name,
)
self._add_to_cache(self.db, ct)
return ct
์๋ง์ ๋ฉ์๋ ์ค์ get_for_model ์ด๋ ๋ฉ์๋๊ฐ ์๋ค.
์ด ํจ์์ ์ธ์๋ก ์ฟผ๋ฆฌ์
์์ ๋ฐ์ ๋ชจ๋ธ์ ์ธ์๋ก ๋๊ฒจ์ ct์ ์ ์ฅํ๋ค.
Logentry์ค์ ์ ๋ง๋ฌด๋ฆฌํด์ค๋ค.

ํ๋ถ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ํ๊ฐ ๋ณํ๋ ๊ฒ์ ๋ง๋ค์ด๋ณด์.
class OrderAdmin(admin.ModelAdmin):
list_filter = ('status',)
list_display = ('fcuser', 'product', 'styled_status', 'action')
change_list_template = 'admin/order_change_list.html' >>>1
actions = [
refund
]
def action(self, obj): >>>> 2.
if obj.status != 'ํ๋ถ':
return format_html(f'<input type="button" value="ํ๋ถ"token interpolation">{obj.id})" class="btn btn-primary btn-sm">')
change_list_template ์ ์๋ก๋ง๋ htmlํ์ด์ง๋ก ์ฐ๊ฒฐํด์ฃผ์๋ค.
actionํจ์๋ฅผ ๋ณด๋ฉด obj๋ฅผ ์ธ์๋ก ๋ฐ๋๋ฐ print๋ฌธ์ผ๋ก ์ฐ์ด๋ณด๋ฉด Order๋ชจ๋ธ์ด ๋์จ๋ค.
{% extends 'admin/change_list.html' %}
{% load static %}
{% block extrahead %}
{{ block.super }}
<script>
function order_refund_submit(obj_id) {
jQuery("#changelist-form").append('<input type="hiden" name="obj_id" value="' + obj_id + '">');
jQuery("#changelist-form").submit();
}
</script>
{% endblock %}
def changelist_view(self, request, extra_context=None):
## ์ํ๋ ๋์
extra_context = { 'title': '์ฃผ๋ฌธ ๋ชฉ๋ก' }
# ์ถ๊ฐ๋ ์ฝ๋
if request.method == 'POST':
obj_id = request.POST.get('obj_id')
if obj_id:
qs = Order.objects.filter(pk=obj_id)
ct = ContentType.objects.get_for_model(qs.model)
for obj in qs:
obj.product.stock += obj.quantity
obj.product.save()
LogEntry.objects.log_action(
user_id = request.user.id,
content_type_id=ct.pk,
object_id=obj.pk,
object_repr='์ฃผ๋ฌธ ํ๋ถ',
action_flag=CHANGE,
change_message='์ฃผ๋ฌธ ํ๋ถ'
)
qs.update(status='ํ๋ถ')
qs์ Order๋ชจ๋ธ์ pk๊ฐ์ด obj_id(request.Post.get)์ธ ๊ฐ์ ์ ์ฅํ๋ค.