Django admin AttributeError: Unable to lookup `FIELD` on 'MODEL_1' on 'MODEL_2' on 'MODEL_3' - django-forms

This answer didn't solve the issue for me, Generating django admin and foreignkey error.
I added a new field over a MODEL_1 everything works fine when I open the table in django dashboard but when I open an entry in MODEL_1 I get the error ```Unable to lookup 'model_1' on MODEL_1 or MODEL_1Admin or MODEL_1Form````
class Battery(TimeStampedModel):
charging_counts = models.IntegerField(default=0)
# tracking details
status_updated_at = models.DateTimeField(null=True, blank=True)
Admin:
class BatteryAdmin(RemoveAddOptionMixin, VogoAbstractBaseModelAdmin):
list_disply = ['charging_counts', 'status_updated_at', ]
search_fields = ()

Related

DRF : CreateAPIView - UNIQUE constraint failed

I am using Django Rest Framework with React for the front.
I want to post Note linked to a ForeignKey User.
models.Note
class Note(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
content = models.TextField(blank=True, default='')
serializers.NoteSerializer
class NoteSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = Note
fields = ('user', 'content')
When I post {user: 1, content: "test"}, I get the following error message:
UNIQUE constraint failed: app_note.user_id
How can I link the new Note to an existing user, posting the user.id?
I think my current code is trying to create a new User Instance...
You are using OneToOneField in Note model. That means a user can have only one note.
use ForeignKey instead to have many notes for single user.

How to get the id of a current object in Django serializers?

I have a model, 'Project'. The idea is that, a user will log in and create a project. After creating, the user will work on this project at any time. Certain details will be saved to other models where I have written custom functions for it in Serializers.py.
In order solve the idea I have, I need to retrieve the id of the current project that the user is currently working on in Serializers.py. Below is my code:
View.py
class MaterialTagExcelViewSet(FilteredModelViewSet):
queryset = MaterialTagExcel.objects.all()
serializer_class = MaterialTagExcelSerializer
permission_classes = (IsAuthenticated,)
http_method_names = ('get', 'head', 'post', 'options', 'patch')
Serializers.py
class MaterialTagExcelSerializer(BaseSerializer):
class Meta:
fields = "__all__"
model = MaterialTagExcel
def create(self, validated_data):
name = validated_data.get('name') # get current material name
if name is not None:
name_tag = MaterialTagExcel.objects.filter(name=name).first() # filter name to check if it already exists
client = self.context['request'].user.profile.client # get current client details
if name_tag is not None: # if name exists
objects = MaterialExcelClient.objects.filter(client_id=client.id, name_id=name_tag.id)
if objects.count() == 0:
material_excel_client = MaterialExcelClient(client_id=client.id, name_id=name_tag.id)
material_excel_client.save() # get current id and mat id and save to material_client_excel
return MaterialExcelClient.objects.filter(name_id=name_tag.id).order_by('-id')[0]
else:
return MaterialExcelClient.objects.filter(client_id=client.id, name_id=name_tag.id).first()
else:
MaterialTagExcel.objects.create(**validated_data)
MaterialTagExcel.objects.all() # save if material is new and does not exist
# return the id of this newly created material
obj = MaterialTagExcel.objects.filter(name=name).order_by('-id')[0]
# save the id of the newly created material and current client id into material_excel_client
material_excel_client = MaterialExcelClient(client_id=client.id, name_id=obj.id)
material_excel_client.save()
return MaterialExcelClient.objects.filter(name_id=obj.id).order_by('-id')[0]
From above serializer, I am able to get the client.id with the help of CurrentUserDefault. In my table user is related to profile and profile is related to client but not project. I tried to with a custom CurrentProjectDefault, but I didnt succeeded. I tried with many online sources to solve my problem.
Is there any way to get the id of the current object from client ?
I am apologizing in advance if the solution to my problem is very simple.
If you would need some more details, kindly write it in comment.
Thanks in advance.
Models.py
class MaterialTagExcel():
name = models.CharField(max_length=255, verbose_name='name', null=False, blank=False)
def __str__(self):
return "Material %s: %s" % (self.id, self.name)
#classmethod
def get_queryset_for_user(cls, user):
return cls.objects.all()
class Project():
client = models.ForeignKey(Client, related_name='projects', on_delete=models.PROTECT)
name = models.CharField(max_length=255)
class ToDo(BaseModel):
project = models.ForeignKey(Project, related_name='todos', on_delete=models.CASCADE)
owner_client = models.ForeignKey(Client, related_name='todos', on_delete=models.CASCADE)
You wish to retrieve the current project the user is working on. The goal of a REST API is to be stateless, which roughly means that the request contains all the necessary information to perform its action without relying on an external context.
This means that you have to provide the current project id in each of your request.
So, in your example, when you want to POST a new MaterialTagExcel, you'll have to provide the Project. You can modify your serializer like this to do so:
class MaterialTagExcelSerializer(BaseSerializer):
project = serializers.PrimaryKeyRelatedField(write_only=True, queryset=Project.objects.all())
class Meta:
fields = "__all__"
model = MaterialTagExcel
def create(self, validated_data):
name = validated_data.get('name')
project = validated_data.pop('project') # A Project object
Now, when you're doing a request, you'll have to specify the property project with the id. of the project the user has selected in the menu.

last_login does not update by API in django rest

I created a simple endpoint to create and update users. It's work fine except for the field last_login that not update when a user login by API.
My example:
My urls:
router.register(r"user", foo.UserViewSet)
My Serializer:
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
email=validated_data["email"],
last_login=validated_data["last_login"],
)
user.set_password(validated_data['password'])
user.save()
return user
class Meta:
model = User
exclude = (
"groups",
"user_permissions",
)
My View:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
pagination_class = StandardPagination
serializer_class = UserSerializer
model = User
def update(self, request, *args, **kwargs):
user = self.get_object()
serializer = self.get_serializer(
user, data=request.data, partial=True
)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
When I log with any user (in API) the field last_login is always null. By django admin is ok.
Update
I had some progress and problems putting the code in my UserViewSet:
def perform_authentication(self, request):
user = request.user
user.last_login = timezone.now()
user.save()
return user
Ok. last_login is registering, but only in user endpoint and every request in this endpoint.
As far as my own investigation on this issue goes, it turns out that last_login field is tightly coupled with default Django authentication system (session authentication), that is why this field is updated when you use Django Admin, as Admin uses session authentication.
In your case, it looks like some other type of authentication is used, and the signal which updates this field is not triggered. See the link below where the signal is handled:
https://github.com/django/django/blob/5f8495a40ab1554e81ac845484da890dd390e1d8/django/contrib/auth/models.py#L14
So, in order to update this field properly you should probably do it manually.
Here is one more discussion on this matter:
last_login field is not updated when authenticating using Tokenauthentication in Django Rest Framework
Maybe it could be the default setting, try this in settings.py:
SIMPLE_JWT = {
// ...
'UPDATE_LAST_LOGIN': True,
// ...
}
source: https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html

File Upload fails using ModelForm - no error messages though

I'm using ModelForms with the generic editing views (create, update, delete). One of my aims in this exercise is to get to know some frameworks (Django + Bootstrap + a plugin (e.g. PDF.js)) and use as little custom code as possible.
I can create a 'document' record through the Admin site and the upload is saved in the 'files' location I set. When I try through my site, no file is uploaded, although the other fields will be updated (evidently the form validates).
(The FileField IS nullable, because I want to be able to have a pointer to a non-digital asset). The relevant code:
# models.py
class document(models.Model):
ref_file = models.FileField(upload_to='documents/', blank=True, null=True)
def get_absolute_url(self):
return reverse('knowledge_manager:doc_detail', kwargs={'pk': self.pk})
# urls.py
urlpatterns = [
url(r'^doc$', views.docIndex.as_view(), name='doc_index'),
url(r'^doc/(?P<pk>\w+)/det', views.docUpdate.as_view(), name='doc_detail'),
url(r'^doc/new/$', views.docCreate.as_view(), name='doc_create'),
url(r'^doc/(?P<pk>\w+)/update', views.docUpdate.as_view(), name='doc_update'),
url(r'^doc/(?P<pk>\w+)/del', views.docDelete.as_view(), name='doc_delete')
]
# views.py
class docIndex(generic.ListView):
model = document
template_name = 'knowledge_manager/_index.html'
context_object_name = 'document_set'
class doc_detail(generic.DetailView):
model = reference
template_name = 'knowledge_manager/doc_detail.html'
context_object_name = 'document'
form_class = doc_form
success_url = reverse_lazy('knowledge_manager:doc_index')
class docCreate(generic.CreateView):
model = document
template_name = 'knowledge_manager/doc_detail.html'
form_class = doc_form
success_url = reverse_lazy('knowledge_manager:doc_index')
class docUpdate(generic.UpdateView):
model = document
template_name = 'knowledge_manager/doc_detail.html'
context_object_name = 'document'
form_class = doc_form
success_url = reverse_lazy('knowledge_manager:doc_index')
class docDelete(generic.DeleteView):
model = document
success_url = reverse_lazy('knowledge_manager:doc_index')
# forms.py
class doc_form(ModelForm):
class Meta:
model = document
fields = '__all__'
Questions:
what do you think is going wrong? Surely ModelForms with FileFields initialise using 'request.FILES' as well as 'instance' and 'request.POST'?
what's a good way to get debugging messages about what is actually
getting posted? Using function views I used to just pop 'print('made it to
here, value X is', value_x) - is there a better way than just overloading the standard functions of ModelForms etc?
I had overlooked this solution (stackoverflow), which pointed out that the form needs this tag to correctly send material to request.FILES.
<form action="" method="post" **enctype="multipart/form-data"**>

django rest framework choosing between two possible views for hyperlinked field

So I have two different API views on to User, one that superusers can use, and one that normal users can use.
At the moment, the problem is that my hyperlinks are going to auth_users view by default, instead of to the users view.
i.e.
'url': 'localhost:8000/auth_users/5/'
instead of
'url': 'localhost:8000/users/5/'
Here are extracts from the relevant files...
* URLS *
router =
routers.SimpleRouter()
router.register(r'auth_users', UserAPI.AdminUserViewSet)
urlpatterns = patterns('',
url(r'^', include(router.urls)),
url(r'^users/?$', UserAPI.CreateOrList.as_view(), name='users'),
url(r'^users/(?P<pk>[0-9]+)/?$', UserAPI.RetrieveUpdateOrDestroy.as_view()),
...
)
* serializer *
class basic_user_serializer(serializers.HyperlinkedModelSerializer):
url = HyperlinkedIdentityField(view_name='users')
class Meta:
model = User
fields = ['url', 'email', 'username']
* views *
class CreateOrList(generics.GenericAPIView):
"""
List all users, or create a new one.
"""
serializer_class = create_user_serializer
class RetrieveUpdateOrDestroy(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = create_user_serializer
I've had a look at the docs (linked below) but am not sure if this is explained...
http://django-rest-framework.org/api-guide/relations.html#hyperlinkedidentityfield
Anyone know how to fix it?
Cheers.
Oh, I fixed it.
I got rid of the auth_user view to see what would happen, and it threw an error page saying it couldn't find 'user-detail'.
I then changed the name of the users view to 'user-detail', re-enabled the auth_user view, and it works properly now.
No idea why, though - didn't I tell it to use 'users' instead of 'user-detail'??

Resources