Simple Django Form - python

I'm trying to implement a Twitter-like follow system (one user can follow and be followed by many other users). I've tried a number of ways, but I keep getting errors. Currently, every time I drop debuggers or print statements throughout the form, I find that I don't ever get into the clean methods, nor is kwargs ever populated with values.
I want to be able to pass in the follower & following as arguments to the Form and just assign them in the __init__ but everything is going wrong. When I get the response back in Javascript (React & Redux), all I'm getting is errors for both follower & following saying "This field is required."
Here's what I've got so far:
Models
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=100, unique=True)
email = models.EmailField(unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
class Meta:
verbose_name = 'user'
verbose_name_plural = 'users'
class UserFollow(models.Model):
follower = models.ForeignKey('User', models.CASCADE, related_name='follows')
following = models.ForeignKey('User', models.CASCADE, related_name='followed_by')
class Meta:
unique_together = ('follower', 'following')
def to_user(self):
return {
'id': self.pk,
'follower': self.follower.pk,
'following': self.following.pk
}
Views
def follow(request, id):
following = User.objects.get(pk=id)
form = UserFollowForm(follower=request.user, following=following)
if form.is_valid():
user_follow = form.save()
return JsonResponse({'user_followed': following.to_user()})
return JsonResponse({'error': form.errors}, status=400)
Forms
class UserFollowForm(forms.ModelForm):
follower = forms.CharField()
following = forms.CharField()
class Meta:
model = UserFollow
fields = ('follower', 'following')
def __init__(self, *args, **kwargs):
self.follower = kwargs.pop('follower', None)
self.following = kwargs.pop('following', None)
super(UserFollowForm, self).__init__(*args, **kwargs)
def clean_follower(self):
return self.follower
def clean_following(self):
return self.following

You haven't passed any data into the form, so it is not bound and will never be validated.
However I don't understand why you want to use a form here at all. You don't seem to want to take posted data from the user, and there is no validation to be done. Just create your UserFollow instance directly.
def follow(request, id):
following = User.objects.get(pk=id)
user_follow = UserFollow.objects.create(follower=request.user, following=following)
return JsonResponse({'user_followed': user_follow.to_user()})

Related

How I can use django ModelForm object and Queryset to do login authentication function

My following question is about how I can develop a function that I can compare a POST request data (ModelForm) and existing data of model in queryset.
This is mi models.py:
class Employee(models.Model):
dni = models.CharField(max_length=9, null=False, blank=False, default="12345678R")
name = models.CharField(max_length=7)
surname = models.CharField(max_length=8)
email = models.CharField(max_length=20)
telefone_number = models.IntegerField()
user_nick = models.CharField(max_length=10, null=False, blank=False, default="user")
password = models.CharField(max_length=20, null=False, blank=False, default="password")
ticket = models.ManyToManyField(Ticket)
forms.py (EmployerLoginForm only to user_nick and password):
class EmployerForm(forms.ModelForm):
class Meta:
model = Employee
fields = "__all__"
class EmployerLoginForm(forms.ModelForm):
class Meta:
model = Employee
exclude = ['dni', 'name', 'surname', 'email', 'telefone_number', 'ticket']
In this case, to develop login function I am using the EmployerLoginForm in views.py:
_logger = nexus_services_logs.Logging(statics.NEXUS_VIEWS_LOGGING_NAME)
_views_manager_service = nexus_services_views_manager.ViewsManagerService()
_auth = nexus_services_auth.Authentication()
class IndexView(View):
def post(self, request, *args, **kwargs):
form = EmployerLoginForm(request.POST)
if(_auth.check_model_employer_authentication(form, _logger, _views_manager_service)):
if(_views_manager_service.validate_form(form, _logger)):
_views_manager_service.save_form(form, _logger)
return redirect('employerPortal')
else:
return redirect('index')
check_model_employer_authentication(form, _logger, _views_manager_service) is the function where I want compare form data and queryset. I find the problem when I cannot compare the objects using for loop (in auth.py):
class Authentication():
def __init__(self):
self.employer_exist = False
def check_model_employer_authentication(self, model, logger, views_manager_service):
queryset_all_employers = Employee.objects.order_by("id")
context_exployers = views_manager_service.build_context_queryset_employers(queryset_all_employers)
for employer in context_exployers["employers"]:
if(employer.user_nick == model.user_nick and employer.password == model.password):
self.employer_exist = True
logger.info_log("Exist nick with similar password")
return True
else:
logger.error_log("Nick or password not exist or coincidence with object in db")
return False
I have tried using a context but not works.

Django forms.ModelChoiceField queryset problem with models.manager

I am having trouble making a ModelChoiceField queryset in a ModelForm. The related model.objects manager has been overridden to filter the results in order to get only instances created by the actual user. Here are my models :
class Bloc(ModelPrive):
TYPE_BLOC = (
('pleinchamps', 'plein champs'),
('tunnel', 'tunnel'),
('pepiniere', 'pépinière'),
('autre', 'autre'),
)
nb_planche = models.IntegerField(null=True)
caracteristique = models.CharField(max_length=200, null= True, blank=True)
geom = models.PolygonField(srid=4326)
type_bloc = models.CharField(max_length=200, blank=True, choices=TYPE_BLOC)
nom = models.CharField(max_length=200, null=True, unique= True)
class ModelPrive(models.Model):
created_by = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL, editable=False)
class Meta:
abstract = True
objects = ModelPriveManager()
class ModelPriveManager(models.Manager):
def get_queryset(self):
user = get_current_user()
return super().get_queryset().filter(created_by=user)
In my manager the get_current_user() returns the actual user that has been intercepted by a custom middleware.
Here is my form :
class BlocFormList(ModelForm):
choix_bloc = forms.ModelChoiceField(queryset = Bloc.objects.all().order_by('nom'), required=True)
class Meta:
model = Bloc
fields = ['choix_bloc']
Here is my view :
def planification(request):
form_bloc = BlocFormList()
if request.method == 'POST':
# some other code
return render(request, 'planification.html', locals())
The problem is, when I do a Bloc.objects.all() in views I get the expected answer (Bloc.objects.filter(created_by=user)) but when it is done inside the queryset of the modelform, it returns nothing (as if there were no active user).
After some checks, I have found that the model form queryset doesn't even go into the manager.
If someone knows how to correct this, I have no more ideas.
Seeing this post Django ModelForm overriding __init__, I finally found my solution by overriding the init of my ModelForm :
class BlocFormList(ModelForm):
blocs = None
choix_bloc = forms.ModelChoiceField(label='Blocs', queryset=blocs, required=True)
def __init__(self, *args, **kwargs):
self.blocs = Bloc.objects.all()
super(BlocFormList, self).__init__(*args, **kwargs)
self.fields['choix_bloc'].queryset = self.blocs
class Meta:
model = Bloc
fields = ['choix_bloc']
This works fine.

Alllow one extra filed into serializer and return validated data with that field in Django Rest Framework

I know on this topic people asked a question before but my case is different and I have implemented almost all the solutions which I found but none of them are worked for me.
First I have defined three classes in models:
models.py
class User(AbstractBaseUser, PermissionsMixin):
""" User Model """
username = None
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
agency = models.ForeignKey('agency.Agency', on_delete=models.CASCADE, null=True)
weekly_email = models.NullBooleanField()
is_create_new_password = models.NullBooleanField(default=True)
is_active = models.BooleanField(default=True)
last_login_time = models.DateTimeField(null=True)
last_login_from = models.CharField(max_length=255, null=True)
created_at = models.DateField(default=timezone.now)
updated_at = models.DateField(default=timezone.now)
created_by = models.IntegerField(null=True)
updated_by = models.IntegerField(null=True)
""" The `USERNAME_FIELD` property tells us which field we will use to log in.
In this case, we want that to be the email field. """
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
""" Tells Django that the UserManager class defined above should manage
objects of this type. """
objects = UserManager()
class Role(models.Model):
""" Role Model """
name = models.CharField(max_length=255, unique=True)
class UserRole(models.Model):
""" User Role Model """
user = models.ForeignKey(User, on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE)
Then I have defined my serializer for user module:
serializers.py
class RegistrationSerializer(serializers.ModelSerializer):
""" Serializers registration requests and creates a new user. """
user_id = serializers.IntegerField(required=False)
email = serializers.EmailField(max_length=255)
name = serializers.CharField(max_length=255)
agency_id = serializers.IntegerField(source='agency.id', required=False)
role = serializers.CharField(source='role.name')
weekly_email = serializers.NullBooleanField()
last_login_time = serializers.DateTimeField(required=False)
last_login_from = serializers.CharField(max_length=255, required=False)
class Meta:
model = User
fields = (
'role', 'user_id', 'email', 'name', 'agency_id', 'weekly_email', 'last_login_time',
'last_login_from'
)
And At the end, I have defined my view file for user creation:
views.py
class UserCreateAPIView(APIView):
""" User create Api view class """
#Allow any user (authenticated or not) to hit this endpoint.
permission_classes = (IsAuthenticated,)
serializer_class = RegistrationSerializer
def post(self, request):
""" create user using following logic. """
request.data['user_id'] = request.user.id
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user)
return Response({'message': response['user']['created'], 'data': serializer.data},
status=status.HTTP_201_CREATED)
Now when I run it everything works fine like user is created, role is created as per my expectations. My view, serializer and models excuted but at the end on this line:
return Response({'message': response['user']['created'], 'data': serializer.data},
status=status.HTTP_201_CREATED)
I am facing error like,
AttributeError: Got AttributeError when attempting to get a value for field `role` on serializer `RegistrationSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `User` instance.
Original exception text was: 'User' object has no attribute 'role'.
I think you need to use ModelSerializer
class RegistrationSerializer(serializers.Serializer):
to
class RegistrationSerializer(serializers.ModelSerializer):

DB not updated on serializer.save()

I am trying to build a api for updating first and last name for my user. The api runs successfully but database is not updated which is the expected behavior
I have written the following API and trying to pass the patch request to it.
class UserSelfUpdateView(UpdateAPIView):
serializer_class = UserUpdateSerializer
permission_classes = [UserPermissions, ]
def update(self, request: Request, *args, **kwargs):
instance = User.objects.filter(id=self.request.user.id)
serializer = UserUpdateSerializer(instance, data=request.data,)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({'success': True}, status=status.HTTP_200_OK)
The serializer for the above request is:
class UserUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields: ('id', 'first_name', 'last_name')
The format in which I am trying to pass my request body is:
{
"first_name": "A",
"last_name": "B"
}
and this is how my model is defined:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=False)
last_name = models.CharField(_('last name'), max_length=30, blank=False)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
'''
Returns the first_name plus the last_name, with a space in between.
'''
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
'''
Returns the short name for the user.
'''
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
'''
Sends an email to this User.
'''
send_mail(subject, message, from_email, [self.email], **kwargs)
When running code with debug pointer results in the no database update but 200 status.
When running code without debug pointer results in 500 status code and following error message in response
AssertionError at /user/me-edit
("Creating a ModelSerializer without either the 'fields' attribute or the 'exclude' attribute has been deprecated since 3.3.0, and is now disallowed. Add an explicit fields = 'all' to the UserUpdateSerializer serializer.",)
Problem resides in the serializer, and concretely, inside this part of the code:
class Meta:
model = User
fields: ('id', 'first_name', 'last_name')
Fields are also a variable defined using =, so the code should look like:
class Meta:
model = User
fields = ('id', 'first_name', 'last_name')
That will help you on solving that AssertionError.

Django REST - Custom Serializer for Full Username

I have an application with Django/Django-REST on the backend with Angular on the front-end. I am looking for the correct way to convert a user ID to a full username for display in an Angular JS modal.
Here is my serializer:
from rest_framework import serializers
from .models import ArtnetTasks
from django.contrib.auth.models import User
class TaskSerializer(serializers.ModelSerializer):
date_assigned = serializers.DateTimeField(format='%Y-%m-%d')
assigned_by_name = serializers.SerializerMethodField('full_username')
assigned_to_name = serializers.SerializerMethodField('full_username')
def full_username(self, id):
user = User.objects.get(id=id)
name = user.first_name + " " + user.last_name
return name
class Meta:
model = ArtnetTasks, Users
fields = ('id', 'headline', 'message', 'assigned_to', 'assigned_to_name', 'assigned_by', 'assigned_by_name', 'date_assigned', )
My Model:
class ArtnetTasks(models.Model):
id = models.IntegerField(primary_key=True)
headline = models.CharField(max_length=75L)
message = models.TextField()
response_message = models.TextField(blank=True)
assigned_to = models.IntegerField(null=True, blank=True)
assigned_by = models.IntegerField(null=True, blank=True)
date_assigned = models.DateTimeField()
date_completed = models.DateTimeField(null=True, blank=True)
is_active = models.IntegerField(null=True, blank=True)
date_updated = models.DateTimeField(null=True, blank=True)
class Meta:
db_table = 'artnet_tasks'
assigned_to and assigned_by are user_id's that correspond with auth_user
It is throwing the following error then promptly breaking the Angular AJAX calls, the error from what I can tell is "argument must be a string or a number\054 not 'dict'"
This is my first project using both Django-REST and Angular and am sure I am missing something obvious.
Thanks in advance!
So, you can not set more than one model on your serializer. Your serializer can only handle one model per time. Another thing, the SerializerMethodField has as parameter self and obj, where, obj is your ArtnetTasks instance. As a better RESTful practice, I recommend you the follow example, if your user is authenticated:
class TaskSerializer(serializers.ModelSerializer):
date_assigned = serializers.DateTimeField(format='%Y-%m-%d')
assigned_by_name = serializers.SerializerMethodField('get_user_full_name')
assigned_to_name = serializers.SerializerMethodField('get_user_full_name')
def get_user_full_name(self, obj):
request = self.context['request']
user = request.user
name = user.first_name + " " + user.last_name
return name
class Meta:
model = ArtnetTasks
fields = ('id', 'headline', 'message', 'assigned_to', 'assigned_to_name', 'assigned_by', 'assigned_by_name', 'date_assigned', )
Better than this, I recommend you to create a simple serializer to the User model, and then , instead to use assigned_by_name and assigned_to_name, you can use:
user = YourUserSerialuzer()
But you will need a relation between User and ArtnetTasks model to do that.
You can see more examples of how do this, here: http://www.django-rest-framework.org/api-guide/relations

Categories