Django log_update() got multiple values for argument 'user' - python

I'm getting TypeError log_update() got multiple values for argument 'user' when trying to create an instance in the database.
Constructor
class ChangeLogManager(models.Manager):
use_in_migration = True
def log_update(user, content_type, object_id, content_object, changes, date_of_change):
return self.model.objects.create(
user = user,
content_type = content_type,
object_id = object_id,
content_object = content_object,
changes = changes,
date_of_change = date_of_change,
)
views
def editUser(request, pk):
# Query appropriate user based on pk returned in url
user = User.objects.get(pk = pk)
# Get the EditUserForm and add the user as instance
edit_user_form = EditUserForm(instance = user)
if request.method == 'POST':
# Bind data to the form class, and add the user as instance
edit_user_form = EditUserForm(request.POST, error_class=DivErrorList, instance = user)
old_user_instance = User.objects.get(pk = pk)
# Validate form inputs
if edit_user_form.is_valid():
# Save edits
edit_user_form.save()
# Log change
ChangeLog.change_message(request.user.id, User, old_user_instance)
else:
# error
context = {
'user': user,
'edit_user_form': edit_user_form,
}
# Render request, template and context
return render(request, 'users/backend/user/user_edit.html', context)
method
def change_message(request, obj, old_instance):
new_instance = obj.objects.get(pk = old_instance.pk)
ct = ContentType.objects.get_for_model(new_instance)
for field in obj._meta.get_fields():
if isinstance(field, models.ManyToOneRel):
continue
old_value = getattr(old_instance, field.name)
new_value = getattr(new_instance, field.name)
if old_value != new_value:
change_message = json.dumps({"field": field.name, "old_value": old_value, "new_value": new_value})
ChangeLog.objects.log_update(
user = request,
content_type = ct.pk,
object_id = new_instance.pk,
changes = change_message,
)
The error happens on the line user = request,. I've tried looking at other threads, and adding both self and moving request as the first parameter in the method without luck. I've also read that its best practice to replace the method parameters with **kwargs, but as I'm quite new, I'm not sure how to retrieve the needed parameters in the method itself.
edit - traceback
[28/Dec/2019 20:53:02] "GET /backend/users/1/edit/ HTTP/1.1" 200 30770
Internal Server Error: /backend/users/1/edit/
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/daniel/Projects/proj/Code/puro/users/views.py", line 191, in editUser
ChangeLog.change_message(request.user.id, User, old_user_instance)
File "/Users/daniel/Projects/proj/Code/puro/utils/models.py", line 63, in change_message
ChangeLog.objects.log_update(
TypeError: log_update() got multiple values for argument 'user'

You need to add self as the first argument to the log_update method and you need to pass the other required arguments to the method
ChangeLog.objects.log_update(
user = request,
content_type = ct.pk,
object_id = new_instance.pk,
content_object=new_instance,
changes = change_message,
date_of_change=datetime.datetime.now()
)

Related

TypeError: __init__() got an unexpected keyword argument 'file'

I'm using Django to develop a platform where users can upload files. This function was working fine for months with no issues, but for some reason now I get this error when trying to upload a file:
Traceback:
Traceback (most recent call last):
File "/home/me/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/me/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/me/project/app/views.py", line 314, in invoke_local
instance = SingleEndForm(file=request.FILES['file'])
Exception Type: TypeError at /invoke_local/
Exception Value: __init__() got an unexpected keyword argument 'file'
My model:
class SingleEnd(models.Model):
file = models.FileField(upload_to="documents/")
email = models.CharField(max_length=100)
def __str__(self):
return self.email
My form:
class SingleEndForm(forms.ModelForm):
class Meta:
# shows which model to use from models.py
model = SingleEnd
# fields = '__all__'
fields = ["file", "email"]
labels = {
"file": "input your fasta/fastq file (min 3 sequences)",
"email": "input your email to get a notification for your results in a timely manner",
}
widgets = {
"email": forms.EmailInput(attrs={"class": "form-control"}),
"file": forms.FileInput(attrs={"class": "form-control"}),
}
My view:
def invoke_local(request):
# path to save inputs
media_path = "/home/me/project/media/documents/"
# path to save outputs
result_path = "/home/me/project/media/results"
if request.method == "POST":
# use the form to upload form info (post) and files
form = SingleEndForm(request.POST, request.FILES)
if form.is_valid():
# saves full form
instance = SingleEndForm(file=request.FILES['file'])
instance.save()
# changes file name if the name is the same
file_name_final = instance.file.name[10:]
# final path
file_path = media_path + file_name_final
else:
raise Http404("Form not entered correctly")
form = SingleEndForm()
return render(request, "invoke_local.html", {"form": form})
I really don't get what I've done wrong.
Based on example in documentation Handling uploaded files with a model you mix two different methods and this makes problem
You can directly write Form
form = SingleEndForm(request.POST, request.FILES)
if form.is_valid():
# saves full form
form.save()
Or you have to create instance of model SingleEnd instead of form SingleEndForm
form = SingleEndForm(request.POST, request.FILES)
if form.is_valid():
# use model
instance = SingleEnd(file=request.FILES['file'])
instance.save()
(but you use form SingleEndForm and this makes problem)

Django / Python - change does not save in database - AttributeError: 'QuerySet' object has no attribute 'reload'

I have a setting that a user can change: send email automatically or manually. For this, I created a database with only 1 row that has the following columns:
class AutoSendMail(models.Model):
auto = models.BooleanField(default=False)
manual = models.BooleanField(default=True)
send_type = (
('manual', 'MANUAL'),
('auto', 'AUTO')
)
type = models.CharField(max_length=6, choices=send_type, default="manual")
def get(self):
new_self = self.__class__.objects.get(pk=self.pk)
# You may want to clear out the old dict first or perform a selective merge
self.__dict__.update(new_self.__dict__)
return reverse("core:autosend", kwargs={"auto": self.auto})
def reload(self):
new_self = self.__class__.objects.get(pk=self.pk)
# You may want to clear out the old dict first or perform a selective merge
self.__dict__.update(new_self.__dict__)
In this, either 'auto' or 'manual' is True, and the other one is False. The 'type' is set to 'auto' or 'manual' accordingly. This setting is used in the rest of the code. The code I have now in my view is:
class AutoSendView(generic.TemplateView):
template_name = 'core/mailbox/autoSendMail.html'
context_object_name = 'autosend'
extra_context = {"mailbox_page": "active"}
model = AutoSendMail.objects.get(id=1)
model.refresh_from_db()
autoSetting = int(model.auto == True)
manualSetting = int(model.manual == True)
def post(self, request, *args, **kwargs):
id_ = self.kwargs.get("pk")
update_type = self.request.POST.get('update_type')
if update_type == 'manual':
logger.info("Set to: manual email send")
model = AutoSendMail.objects.filter(id=1)
model.manual = True
model.auto = False
model.type = "manual"
for object in model:
object.save()
model.reload()
return redirect("core:autosend")
elif update_type == 'auto':
logger.info("Set to: auto email send")
model = AutoSendMail.objects.filter(id=1)
model.manual = False
model.auto = True
model.type = "auto"
for object in model:
object.save()
model.reload()
return redirect("core:autosend")
My problem is that what a user changes in the setting is not saved in the database (sqlite3). And I'm not sure why not. Because when I try this in my python console, it does work. So I do something wrong.
With the code above I get an error saying:
ERROR Internal Server Error: /mailbox/autosend
Traceback (most recent call last):
File "C:\Users\Portal\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\Portal\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Portal\venv\lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view
return view_func(request, *args, **kwargs)
File "C:\Users\Portal\venv\lib\site-packages\django\views\generic\base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\Portal\venv\lib\site-packages\django\views\generic\base.py", line 101, in dispatch
return handler(request, *args, **kwargs)
File "C:\Users\portal\core\views.py", line 200, in post
model.reload()
AttributeError: 'QuerySet' object has no attribute 'reload'
ERROR "POST /mailbox/autosend HTTP/1.1" 500 2657
Someone has an idea how to deal with this? When I remove the 'reload' it gives the error 'QuerySet' object has no attribute 'save'. If I remove the 'save()' also, it does not save the change
filter(...) will return a Queryset, but get(...) returns the object. So replace:
model = AutoSendMail.objects.filter(id=1)
with
model = AutoSendMail.objects.get(id=1)
Alternate
I think your codes are very redundant and unoptimized. I think you can use the following code:
if update_type == 'auto':
model = AutoSendMail.objects.filter(id=1).update(type="auto", auto=True)

Follow system returning User matching query does not exist error

I have been working on a follow system on django which needs to have the same functionality as instagram's one; meaning that a user can follow and be followed by other other users and in a user's profile there is a follower count that displays the number of followers a user has, together with a following count that displays the number of people a user is following.
So everything was working good and there was one missing functionality to complete the follow system and it was the follower count. To get this done, I created a signals.py file, but as soon as I did that The follow/unfollow button was not working due to a internal server 500 error, so after some investigation I realized that the 500 error was happening because there is this error DoesNotExist at /accounts/follow/username User matching query does not exist. Why is it poping that error, can it be solved?
signals.py
#receiver(m2m_changed, sender = Following.followed.through) # which list is changed
def add_follower(sender, instance, action, reverse, pk_set, **kwargs):
followed_users = [] # list of users main (logged ) user have followed
logged_user = User.objects.get(username = instance) # user who followed other users
for i in pk_set:
user = User.objects.get(pk = i)
following_obj = Following.objects.get(user = user)
followed_users.append(following_obj)
if action == "pre_add":
for i in followed_users:
i.follower.add(logged_user)
i.save()
if action == "pre_remove":
for i in followed_users:
i.follower.remove(logged_user)
i.save()
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
connection = models.CharField(max_length = 100, blank=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
def __str__(self):
return f'{self.user.username} Profile'
class Following(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed = models.ManyToManyField(User, related_name="followed")
follower = models.ManyToManyField(User, related_name="follower")
#classmethod
def follow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.add(another_account)
print("followed")
#classmethod
def unfollow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.remove(another_account)
print("unfollowed")
def __str__(self):
return f'{self.user.username} Profile'
views.py
def follow(request, username):
main_user = request.user
to_follow = User.objects.get(username=username)
following = Following.objects.filter(user = main_user, followed = to_follow)
is_following = True if following else False
if is_following:
Following.unfollow(main_user, to_follow)
is_following = False
else:
Following.follow(main_user, to_follow)
is_following = True
resp = {
'following': is_following,
}
response = json.dumps(resp)
return HttpResponse(response, content_type="application/json")
def profile(request, username):
user = User.objects.filter(username=username)
if user:
post_owner = get_object_or_404(User, username=username)
user = user[0]
is_following = Following.objects.filter(user=request.user, followed=user)
following_obj = Following.objects.get(user=user)
follower = following_obj.follower.count()
following = following_obj.followed.count()
args1 = {
'user_obj':user,
'post_owner': post_owner,
'follower': follower,
'following': following,
'connection': is_following,
}
else: return HttpResponse("NO SUCH USER")
return render(request, 'profile.html', args1)
profile.html
<head>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel#1.8.1/slick/slick.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel#1.8.1/slick/slick.min.js"></script>
</head>
<body>
{% if connection %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' user_obj.username %}">Unfollow</a>
{% elif not connection %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' user_obj.username %}">Follow</a>
{% endif %}
<script type="text/javascript">
$("#follow").click(function(e){
e.preventDefault();
var href = this.href;
$.ajax({
url : href,
success : function(response){
if(response["following"]){
$("#follow").html("Unfollow");
}
else{
$("#follow").html("Follow");
}
}
})
})
</script>
</body>
traceback
Traceback (most recent call last):
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\USER\startup\gstartup\accounts\views.py", line 110, in follow
Following.unfollow(main_user, to_follow)
File "C:\Users\USER\startup\gstartup\accounts\models.py", line 43, in unfollow
obj.followed.remove(another_account)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\fields\related_descriptors.py", line 961, in remove
self._remove_items(self.source_field_name, self.target_field_name, *objs)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\fields\related_descriptors.py", line 1179, in _remove_items
signals.m2m_changed.send(
File "C:\Users\USER\Envs\startup\lib\site-packages\django\dispatch\dispatcher.py", line 173, in send
return [
File "C:\Users\USER\Envs\startup\lib\site-packages\django\dispatch\dispatcher.py", line 174, in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
File "C:\Users\USER\startup\gstartup\accounts\signals.py", line 16, in add_follower
logged_user = User.objects.get(username = instance) # user who followed other users
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\query.py", line 415, in get
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
If you have any questions or need to see more code please let meknow in the comments;)
I am a bit confuse about the sender, but I am pretty sure your instance variable is an object of User class and for filtering you should use
logged_user = User.objects.get(username = instance.username)
note1: If instance is an User instance, I don't see why the query is needed.
note2: If it's not an User instance, check it's class and use field name instead of instance.
DoesNotExist Error
The issue you seem to be encountering is here:
to_follow = User.objects.get(username=username) located in your views.py.
This will raise a DoesNotExist error and respond with a 500 if object is not found. Consider using get_object_or_404 instead.
Consider removing the signal. Count method as detailed in the example below should be efficient enough. If any more is necessary consider higher level caching solution instead.
Idiosyncrasies
Consider using a custom User
model
instead of Profiles.
Consider using manager
methods
instead of class methods.
Consider using class based
views
with mixins and separating business logic into contextual methods to
make unit testing and debugging easier.
Consider writing unit
tests
for each of your model and view methods to more easily identify bugs
when they happen.
Your models.py should be refactored to the something resembling the following to reduce complexity and increase data integrity:
class UserManager(models.Manager):
def follow(user, user_to_follow):
obj, created = self.objects.get_or_create(user = user)
return self.profile.following.add(user, user_to_follow)
def unfollow(self, user)
obj, created = self.objects.get_or_create(user = user)
return self.following.remove(profile, user_to_unfollow)
class User(AbstractUser):
connection = models.CharField(max_length=100, blank=True)
following = models.ManyToManyField(self, "following")
followers = models.ManyToManyField(self, "followers")
objects = UserManager()
def follower_count(self):
return User.objects.filter(following=self).count()
def following_count(self):
return User.objects.filter(followers=self).count()
def __str__(self):
return f'{self.user.username} Profile'
# Profile.objects.follow(user, user_to_follow)
# Profile.objects.unfollow(user, user_to_follow)
# profile.follower_count()
# profile.following_count()
References
get object or 404
Custom User Models: https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project
Manager Methods: https://docs.djangoproject.com/en/3.0/topics/db/managers/#adding-extra-manager-methods
Unit Tests: https://docs.djangoproject.com/en/dev/topics/testing/overview/
Unit Test for View example: https://docs.djangoproject.com/en/3.0/intro/tutorial05/#testing-the-detailview
DetailView code example for domain logic separation: https://github.com/django/django/blob/b9cf764be62e77b4777b3a75ec256f6209a57671/django/views/generic/detail.py#L8-L100
Class based views: https://docs.djangoproject.com/en/3.0/topics/class-based-views/

Django 'NoneType' object has no attribute 'obj'

I know there are a few posts about this very same problem but the solution is to be found in some error made in the code that I can't figure out. So I'm posting here what I have written so far, hoping for your help.
I have a class Node and I get the error stated in the title when I perform a POST.
This is my code:
class NodeResource(ModelResource):
class Meta:
queryset = api.models.Node.objects.all()
resource_name = _Helpers.node_resource_name
always_return_data = True
# Allow retrieving large quantities of nodes at once.
limit = 250
max_limit = 0
filtering = {'name', 'is_ulg', 'latitude', 'longitude'}
allowed_methods = ['get', 'post']
authentication = Authentication()
authorization = Authorization()
def obj_create(self, bundle, **kwargs):
node = api.models.Node(name=bundle.data['name'],
is_ulg=bundle.data['is_ulg'],
latitude=bundle.data.get("latitude"),
longitude=bundle.data.get("longitude"))
node.save()
The model is the following:
class Node(models.Model):
"""
Represents a node in the graph.
"""
name = models.CharField(max_length=255)
is_ulg = models.BooleanField(default=False, verbose_name='Is this node a member of the ULg?')
latitude = models.FloatField()
longitude = models.FloatField()
def __str__(self):
return self.name
class Meta:
ordering = ['name']
unique_together = ("latitude", "longitude")
When I perform a post with the following json
{"name":"Node name","latitude": "2.4567", "longitude":"2.345", "is_ulg":false}
The node is correctly created, but I always get the error stated in the title. The full error is the following:
{"error_message":"'NoneType' object has no attribute 'obj'","traceback":"Traceback (most recent call last):\n\n File \"\/usr\/lib\/python2.7\/site-packages\/tastypie\/resources.py\", line 202, in wrapper\n response = callback(request, *args, **kwargs)\n\n File \"\/usr\/lib\/python2.7\/site-packages\/tastypie\/resources.py\", line 433, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n File \"\/usr\/lib\/python2.7\/site-packages\/tastypie\/resources.py\", line 465, in dispatch\n response = method(request, **kwargs)\n\n File \"\/usr\/lib\/python2.7\/site-packages\/tastypie\/resources.py\", line 1347, in post_list\n updated_bundle = self.full_dehydrate(updated_bundle)\n\n File \"\/usr\/lib\/python2.7\/site-packages\/tastypie\/resources.py\", line 853, in full_dehydrate\n bundle.data[field_name] = field_object.dehydrate(bundle, for_list=for_list)\n\n File \"\/usr\/lib\/python2.7\/site-packages\/tastypie\/fields.py\", line 116, in dehydrate\n current_object = bundle.obj\n\nAttributeError: 'NoneType' object has no attribute 'obj'\n"}
Any idea what I'm doing wrong?
Thanks!
Your object_create function is implicitly returning None, but Tastypie is expecting it to return a bundle. See how it is implemented in the docs example.
However, since it doesn't seem like you're using non-ORM data, you could just skip obj_create and let Tastypie create the resource for you.

Django Testing KeyError When Retrieving Header from Request Object

So I'm trying to confirm the location of a given view during testing. The docs say:
You can also use dictionary syntax on the response object to query the
value of any settings in the HTTP headers. For example, you could
determine the content type of a response using
response['Content-Type'].
However, when I put it to use I'm getting a key error. Help please.
Test:
def test_normal_rewardstore_usage(self):
logged_in = self.client.login(username=self.u1.username, password="psst")
response = self.client.get(reverse('rewards:rewardstore'))
location = "http://testserver%s" % (reverse('rewards:rewardpage', kwargs={'company':self.r1.company.slug, 'slug':self.r1.slug}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Location'], location)
Error:
Traceback (most recent call last):
File "/app/rewards/tests/test_views.py", line 58, in test_normal_rewardstore_usage
self.assertEqual(response['Location'], location)
File "/app/.heroku/python/lib/python2.7/site-packages/django/http/response.py", line 189, in __getitem__
return self._headers[header.lower()][1]
KeyError: 'location'
View:
def RewardStore_Index(request, template='rewards/reward-store.html', page_template='rewards/rewards_page.html'):
user = User.objects.get(pk=request.user.pk)
contact = Contact.objects.get(user__pk=request.user.pk, is_active=True)
if request.user.is_authenticated():
a = Member.objects.get(pk=request.user.pk)
a = a.account_verified
rewards = Reward.objects.filter(country__iso=contact.get_country)
else:
a = False
g = GeoIP()
c = g.country(request.user)
c = c['country_code']
rewards = Reward.objects.filter(country__iso=c)
context = {
'targetuser': request.user,
'rewards': rewards,
'page_template': page_template,
'email_authenticated': True if a else False,
'notifications': NotificationMap.objects.filter(user__pk=request.user.pk, read=False).prefetch_related('notification', 'notification__users')
}
if request.is_ajax():
template = page_template
return render_to_response(
template, context, context_instance=RequestContext(request))
The headers made available in the response object will vary depending on the server used (source), so it wouldn't surprise me if the django test runner doesn't send back all the headers that you see in production. Also, Location is generally used with redirecting responses, and you're asserting that you receive a 200 first. Are you sure that you should be expecting a Location header in this circumstance?

Categories

Resources