django rest api call admin action - python

i created a simple model and created an admin action for it. Then i installed dango-rest and connected to model so i can use it from another machine with rest api calls. Is there a way i can call the admin action as well?
Here is my sample:
models.py
from django.db import models
class my_model(models.Model):
my_id = models.CharField(primary_key = True, max_length=20)
my_line = models.CharField(max_length=20, default='#')
my_description = models.CharField(max_length=255)
admin.py
from django.contrib import admin, messages
from .models import my_model
def precheck_action(modeladmin, request, queryset):
for obj in queryset:
if obj.my_line == 'second step':
obj.my_description = 'provided'
else:
obj.my_description = 'waithing for second step'
obj.save()
class my_form((forms.ModelForm):
class Meta:
model = int_unmanaged
fields = '__all__'
class my_form_admin(admin.ModelAdmin):
form = my_form
list_display = ('my_id', 'my_line','my_description')
actions = [precheck_action]
admin.site.register(my_form, my_form_admin)
Any help on solving this or maybe a better way of doing it would be great.
Thank!

Related

Django not showing a model in admin page

I have created a new model for my app Consumptions but it doesn't show up.
I know that I have to put it on the admin.py page but still not working.
I don't know what could be happening
This is my models.py page:
from logs.mixins import LogsMixin
# Other models
class MF(LogsMixin, models.Model):
"""Definición del modelo de Proveedor."""
name = models.CharField("Nombre", null=False, default="MF", max_length=50)
class Meta:
verbose_name = 'Módulo formativo'
verbose_name_plural = 'Módulos formativos'
def __str__(self):
return self.name
# Other models
And this is my admin.py page:
from django.contrib import admin
from .models import Provider, Consumption, Message, Course, Call, Platform, MF
admin.site.register(Provider)
admin.site.register(Consumption)
admin.site.register(Message)
admin.site.register(Course)
admin.site.register(Call)
admin.site.register(Platform)
admin.site.register(MF)
As you can see is not my only model, I do the same with all of them but the MF one is not showing up on the admin page.
What am I doing wrong?
Try following approach:
class ProviderAdmin(admin.ModelAdmin):
model = Provider
admin.site.register(Provider, ProviderAdmin)
In ProviderAdmin class you may specify filters, search fields or empty value handling:
search_fields = ('',)
list_filter = ('',)
empty_value_display = 'empty'

I want to create and update UserProfile object with OneToOne User object field and create a api in Django rest framework

I'm new in Django rest framework, I tried my whole day but can't do it,I want to do full crud operation in my UserProfile Model which have a OneToOne field user, User can only update their own profile and in UserProfile create or update user shouldn't update User[username], How can i achieve it Please Help me
*** serializers.py ***
from rest_framework import serializers
from product.models import UserProfile
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
read_only_fields = ['username','password', ]
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(many=False)
class Meta:
model = UserProfile
fields = "__all__"
def create(self, validated_data):
user_data = validated_data.pop('user')
user_instance = User.objects.get(
username=user_data['username'])
user_instance.save()
user_profile_instance = UserProfile.objects.create(
**validated_data, user=user_instance)
user_profile.save()
return user_profile
*** views.py ***
from django.shortcuts import render
from .serializers import UserProfileSerializer
from rest_framework.views import APIView
from rest_framework import generics, permissions
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth.models import User
from product.models import UserProfile
# Create your views here.
class CreateUserView(generics.ListCreateAPIView):
serializer_class = UserProfileSerializer
permission_classes = [permissions.IsAuthenticated,]
def get_queryset(self):
user = self.request.user
return UserProfile.objects.filter(user = user)
*** models.py ***
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user_profile', on_delete=models.CASCADE)
country = models.CharField(max_length=50, default='India')
city = models.CharField(max_length=100, default='')
phone = models.CharField(max_length=15,default='')
image = models.ImageField(upload_to='profile_image', blank=True)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username
For Authentication you can use token based authentication(like jwt)
and for username you can use read_only=True
no need to send the password for get request
to update profile you need to handle put/post methods
CLEANED Serializers:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
read_only_fields = ['username','password']
class UserProfileSerializer(serializers.ModelSerializer):
# REMOVED all unecessary overrides
user = UserSerializer(read_only=True)
class Meta:
model = UserProfile
fields = "__all__"
Views:
class UserProfileViewSet(viewsets.GenericViewSet,
mixins.UpdateModelMixin):
# Changed inherited class and class NAME !
# I assume that your endpoint is something like /users/me/profile
# I think you want only to update user profile
# Listing or creating profile here is bad - user should have only ONE profile
# and you should do this on user model post_save signal
serializer_class = UserProfileSerializer
permission_classes = [permissions.IsAuthenticated,]
def get_object(self):
return self.request.user.user_profile
This setup will allow you to update profile and only profile data
In your models file you can make signal listener for automatically creating UserProfile object on User object create.
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)

How do i make self.request.user.account refer to the new inherited Account?

I am using a ready module "account" and I want to supplement it with the help of inheritance with another attribute "photo". In models.py I create class Account, that inherits from Account from "account" module.
extended_account/models.py
from django.db import models
from account.models import Account
class Account(Account):
photo = models.URLField(blank=True, default="default")
But in views.py I have no idea how to chains my own Account model with PhotoView. self.request.user.account still refers to the Account from "account" model and has no "photo" attribute.
How do i make self.request.user.account refer to the new Account in extended_account/models.py?
extended_account/views.py
from django.views.generic.edit import FormView
from account.mixins import LoginRequiredMixin
from extended_account.forms import PhotoForm
class PhotoView(LoginRequiredMixin, FormView):
template_name = "account/new_photo.html"
form_class = PhotoForm
def get_initial(self):
initial = super(PhotoView, self).get_initial()
initial["photo"] = self.request.user.account.photo
return initial
def update_account(self, form):
fields = {}
if "photo" in form.cleaned_data:
fields["photo"] = form.cleaned_data["photo"]
if fields:
account = self.request.user.account
for k, v in fields.items():
setattr(account, k, v)
account.save()
extended_account/forms.py
class PhotoForm(forms.Form):
photo = forms.URLField(required=False)
First of all, I'd rename the new account model, so you can have a clear difference between the two.
Then, you can use a ForeignKey instead of inheriting the class. It'd look like this:
from django.db import models
from account.models import Account
class ExtendedAccount(models.Model):
account = models.ForeignKey(Account,
on_delete=models.CASCADE,
related_name="extended_data")
photo = models.URLField(blank=True, default="default")
# If you want to add more fields to the account model, do it here
Once you have this class, you can create a ModelForm for this class:
from django.forms import ModelForm
from .models import ExtendedAccount
class ArticleForm(ModelForm):
class Meta:
model = ExtendedAccount
fields = ['photo']
Now, if you want to access the photo of the model, just do it as a normal ForeignKey:
a = Account() # Complete the required fields
a.extended_data.photo

How do I get the checkboxselectmultiple formfield_overrides to show on both of my models in a manytomany relationship?

So here is the code that I am working with right now
models.py
from django.db import models
class Building(models.Model):
name = models.TextField(max_length=60)
def __str__(self):
return self.name
class Charge(models.Model):
item = models.CharField(max_length=60)
cost = models.CharField(max_length=15)
last_updated = models.DateField(default='',auto_now=True)
buildings = models.ManyToManyField(Building)
def __str__(self):
return self.item
admin.py
from django.contrib import admin
from rlscharges.models import Charge, Building
from django.db import models
from django.forms import CheckboxSelectMultiple
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {'widget': CheckboxSelectMultiple},
}
class BuildingInline(admin.TabularInline):
model = Charges.building.through
class BuildingAdmin(MyModelAdmin):
fields = ['name']
inlines = [BuildingInline]
admin.site.register(Charge, MyModelAdmin)
admin.site.register(Building, BuildingAdmin)
I basically just want the checkboxselectmultiple to show up on the Charge and Building models admin pages. Right now the checkbox only shows up on the Charge model and the TabularInline shows up on the Building model. Is there a way to get formfield_overrides to apply to the BuildingInline so it shows the checkboxes and not the TabularInline? Or do I need to do something to the relationship of the models? I apologize ahead of time if this is a stupid question, I am just getting started with django.

How to auto insert the current user when creating an object in django admin?

I have a database of articles with a
submitter = models.ForeignKey(User, editable=False)
Where User is imported as follows:
from django.contrib.auth.models import User.
I would like to auto insert the current active user to the submitter field when a particular user submits the article.
Anyone have any suggestions?
Just in case anyone is looking for an answer, here is the solution i've found here:
http://demongin.org/blog/806/
To summarize:
He had an Essay table as follows:
from django.contrib.auth.models import User
class Essay(models.Model):
title = models.CharField(max_length=666)
body = models.TextField()
author = models.ForeignKey(User, null=True, blank=True)
where multiuser can create essays, so he created a admin.ModelAdmin class as follows:
from myapplication.essay.models import Essay
from django.contrib import admin
class EssayAdmin(admin.ModelAdmin):
list_display = ('title', 'author')
fieldsets = [
(None, { 'fields': [('title','body')] } ),
]
def save_model(self, request, obj, form, change):
if getattr(obj, 'author', None) is None:
obj.author = request.user
obj.save()
Let's say that user B saves a record created by user A. By using this approach above the record will be saved with user B. In some scenarios this might not be the best choice, because each user who saves that record will be "stealing" it. There's a workaround to this, that will save the user only once (the one who creates it):
models.py
from django.contrib.auth.models import User
class Car(models.Model):
created_by = models.ForeignKey(User,editable=False,null=True,blank=True)
car_name = models.CharField(max_length=40)
admin.py
from . models import *
class CarAdmin(admin.ModelAdmin):
list_display = ('car_name','created_by')
actions = None
def save_model(self, request, obj, form, change):
if not obj.created_by:
obj.created_by = request.user
obj.save()
If you don't want to keep foreignkey in you model to user, then in your admin.py override save method
obj.author = request.user.username
obj.save()
This will store the username who is logged in your db.
It's time for a better solution override the get_form method
let's say we have this model
models.py
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=256)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
admin.py
class PostAdmin(admin.ModelAdmin):
# you should prevent author field to be manipulated
readonly_fields = ['author']
def get_form(self, request, obj=None, **kwargs):
# here insert/fill the current user name or id from request
Post.author = request.user
return super().get_form(request, obj, **kwargs)
def save_model(self, request, obj, form, change):
obj.author = request.user
obj.last_modified_by = request.user
obj.save()
admin.site.register(Post, PostAdmin)
As per http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.prepopulated_fields you can't use ForeignKey with the prepopulated_field admin directive, alas
But this thread might help you. In my answer I also link to a Google-scanned version of Pro Django, which has a great solution for this kind of thing. Ideally, am sure it's better if you can buy the book, but Google seems to have most of the relevant chapter anyway.
You can't do it directly. However you can achieve this creating middleware and using current user as global variable. But there is a package already doing it : django-currentuser
First install it then
setting.py
MIDDLEWARE = (
...,
'django_currentuser.middleware.ThreadLocalUserMiddleware',
)
and import it in the model file
from django_currentuser.middleware import ( get_current_user, get_current_authenticated_user)
And use;
class Foo(models.Model):
created_by = CurrentUserField()
updated_by = CurrentUserField(on_update=True)

Categories