I want to show User profile in url /account/profile.
I have a detail class based view,
class UserDetail(generic.DetailView):
model = User
slug_field = 'username'
slug_url_kwarg = 'username'
template_name = 'myuser/user_detail.html'
I have a error:
AttributeError at /accounts/profile/
Generic detail View UserDetail must be called with either an object pk or a slug.
How can I charge the username without pass it like parameter in the url?
(ie: /account/prifle/username), the user is already authenticated.
I see something similar here: http://programtalk.com/vs2/?source=python/12247/horas/apps/profiles/views.py but doesn't work to me.
I tried modify get_queryset, dispatch, and nothing work, I don't know where can modify to get the right result.
Any idea? Thanks
That code is very bizarre and you should not follow it. Overriding get_object is the right idea in your case though; but that method should always actually return an object.
class UserDetail(generic.DetailView):
model = User
def get_object(self, *args, **kwargs):
return self.request.user
Related
I'm still struggling with django-filter. I have my filter defined below
class MasterListFilter(django_filters.FilterSet):
project = django_filters.ModelChoiceFilter(
label='Projects',
name='project_fkey',
queryset=Project.objects.filter(deleted__isnull=True)
)
class Meta:
model = Task
fields = ['project']
#property
def qs(self):
parent = super(MasterListFilter, self).qs
user = get_current_user()
return parent.filter(master=True, deleted__isnull=True, user_fkey=user.id)
This works perfectly fine. However I also want to filter the dropdown filter (ie the Project queryset) by the current user. As my user is logged in and authenticated, I believe the user details should be attached to the request.
According to the django-filter docs
The FilterSet may be initialized with an optional request argument. If
a request object is passed, then you may access the request during
filtering. This allows you to filter by properties on the request,
such as the currently logged-in user or the Accepts-Languages header.
So it would seem that the request is there, but I can't work out how to access it as an argument of the FilterSet, nor have I been able to find any examples in the docs or anywhere else in my travels as to how to do it. So if anyone can give me any clues at all, I really would appreciate the help.
Edit
Thanks Willem for the information and advice. Very much appreciated. However I think I may not have explained myself clearly. The problem is not filtering the qs
#property
def qs(self):
parent = super(MasterListFilter, self).qs
user = get_current_user()
return parent.filter(master=True, deleted__isnull=True, user_fkey=user.id)
this bit works fine although I will change it to use the self.request.user as suggested along with capturing any requests that are None. This portion returns my results table that gets rendered in my hmtl page. In this case it is a list of tasks that belong to various projects. What I want to be able to do is give the users a dropdown list at the top of the page which has a list of projects that they can choose from and thereby filter the results table by individual projects. (Projects being the parent model.) This part of the code:
class MasterListFilter(django_filters.FilterSet):
project = django_filters.ModelChoiceFilter(
label='Projects',
name='project_fkey',
queryset=Project.objects.filter(deleted__isnull=True)
)
does achieve this to a point in that it gives a list of all projects that have, in this case, not been deleted. Unfortunately the users are able to create their own projects, each of which has a foreign key back to the user who created it. Therefore, in addition to displaying projects that have not been deleted, I also want to show only the projects that belong to the current user.
No doubt I am missing something here, but my understanding is that django_filters.FilterSet has the request as a property, but if I try to use 'user = self.request.user' in this part of the class, I get an error saying self is not defined (and looking at it, it clearly isn't.) Frankly I'm now a bit stumped and really need some advice on this part of the code.
In short: you can access the request with self.request. If no request is given, then self.request is None.
The request is an attribute of the self. So you can obtain this with self.request.user:
#property
def qs(self):
parent = super(MasterListFilter, self).qs
user = self.request.user # unsafe (!) since request can be None!
return parent.filter(master=True, deleted__isnull=True, user_fkey=user.id)
Note however that the request can be None. So it is better to guard against that, like:
#property
def qs(self):
parent = super(MasterListFilter, self).qs
if self.request:
user = self.request.user
else:
user = None
if user and user.is_authenticated():
return parent.filter(master=True, deleted__isnull=True, user_fkey=user.id)
else:
# do something if no request, or no logged in user
# for example
return parent.filter(master=True, deleted__isnull=True)
Or in a more compact form:
#property
def qs(self):
parent = super(MasterListFilter, self).qs
filters = dict(master=True, deleted__isnull=True)
user = getattr(self.request, 'user', None)
if user and user.is_authenticated():
filters['user_fkey'] = user.id
return parent.filter(**filters)
Since obtaining the user is a rather common operation, we can implement a mixin for this:
class UserFilterMixin(object):
#property
def current_user(self):
return getattr(self.request, 'user', None)
You can then use the mixin, and thus obtain the user with self.current_user.
To filter your list of projects by the request.user, you need to provide a callable as the queryset argument. I'm not familiar with your project, but the code should look something like:
def requested_projects(request):
if request is None:
return Projects.objects.none()
return Project.objects.filter(deleted__isnull=True, user_fkey=request.user)
class MasterListFilter(django_filters.FilterSet):
project = django_filters.ModelChoiceFilter(
label='Projects',
name='project_fkey',
queryset=requested_projects,
)
...
I'm new to the Django Framework and one thing bothers me.
I want a simple Rest Call:
www.abc.com/users/1/cantonments/1/
If i use 'pk' in the url pattern everything works out of the box (pk, pk1, pk2....).
But i have some permission functionality which expects the parameters in kwargs in the form 'upk' and 'cpk' for user and cantonment. So if i change pk to upk everything breaks. Somehow the url needs ONE pk.
This works:
url(r'^users/(?P<pk>[0-9]+)/cantonments/(?P<cpk>[0-9]+)/$',
views.CantonmentDetail.as_view()),
This doesnt:
url(r'^users/(?P<upk>[0-9]+)/cantonments/(?P<cpk>[0-9]+)/$',
views.CantonmentDetail.as_view()),
Is there any way to have an url pattern that does not need one entry with pk?
P.S. The error:
Expected view CantonmentDetail to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
EDIT:
My view is simple:
# Authenticated User can show Cantonment Detail
class CantonmentDetail(generics.RetrieveAPIView):
serializer_class = serializers.CantonmentSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
return Cantonment.objects.filter(pk=self.kwargs['cpk'])
Edit2:
I changed get_queryset to get object and it works.
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
obj = queryset.get(pk=self.kwargs['cpk'])
return obj
Edit3:
Using
lookup_url_kwarg = "cpk"
in the class works as well.
You can send optional pk using get method with your url like
www.abc.com/users/1/cantonments/?&upk=1
and url should be
url(r'^users/(?P<pk>[0-9]+)/cantonments/$',
views.CantonmentDetail.as_view()),
and views.py
def view_name(request, pk=None):
upk = request.GET.get('upk')
May be in your view you are accessing pk variable
urls.py
url(r'^users/(?P<upk>[0-9]+)/cantonments/(?P<cpk>[0-9]+)/$',
views.CantonmentDetail.as_view()),
views.py
class your_class_name(ListView):
def view_name(self):
upk=self.kwargs['upk']
cpk=self.kwargs['cpk']
print upk, cpk
...
Hope this is helps you
The upk doesn't make any difference to the lookup (because a primary key identifies a single object by design).
So for the view, the lookup_field needs to be set to 'cpk' and everything works.
Did you changed your view with the new names of the variables?
If you have url like this:
url(r'^users/(?P<upk>[0-9]+)/cantonments/(?P<cpk>[0-9]+)/$',
views.CantonmentDetail.as_view()),
You shouls update your view like this:
def view_name(request, upk=None, cpk=None):
...
I'm wondering how to change the behavior of a form field based on data in the request... especially as it relates to the Django Admin. For example, I'd like to decrypt a field in the admin based on request data (such as POST or session variables).
My thoughts are to start looking at overriding the change_view method in django/contrib/admin/options.py, since that has access to the request. However, I'm not sure how to affect how the field value displays the field depending on some value in the request. If the request has the correct value, the field value would be displayed; otherwise, the field value would return something like "NA".
My thought is that if I could somehow get that request value into the to_python() method, I could directly impact how the field is displayed. Should I try passing the request value into the form init and then somehow into the field init? Any suggestions how I might approach this?
Thanks for reading.
In models.py
class MyModel(models.Model):
hidden_data = models.CharField()
In admin.py
class MyModelAdmin(models.ModelAdmin):
class Meta:
model = MyModel
def change_view(self, request, object_id, extra_context=None):
.... # Perhaps this is where I'd do a lot of overriding?
....
return self.render_change_form(request, context, change=True, obj=obj)
I haven't tested this, but you could just overwrite the render_change_form method of the ModelAdmin to sneak in your code to change the field value between when the change_view is processed and the actual template rendered
class MyModelAdmin(admin.ModelAdmin):
...
def render_change_form(self, request, context, **kwargs):
# Here we have access to the request, the object being displayed and the context which contains the form
form = content['adminform'].form
field = form.fields['field_name']
...
if 'obj' in kwargs:
# Existing obj is being saved
else:
# New object is being created (an empty form)
return super(MyModelAdmin).render_change_form(request, context, **kwargs)
I'm trying to implement some customize login through the custom methods in Django's models. I want to know if its possible to:
Get request.user in a custom method
Get the user that made the request in the method
Or pass an argument to the custom method
Thinking in doing something like this:
class OneModel(models.Model):
(...)
def viewed(self):
profile = request.user.profile
viewed = self.viewed_episodes.filter(user=profile).exists()
if viewed: return True
else: return None
Another possibility that came to my mind is this:
class OneModel(models.Model):
(...)
def viewed(self, user):
profile = user.profile
viewed = self.viewed_episodes.filter(user=profile).exists()
if viewed: return True
else: return None
But I think neither of this are possible. Maybe what I need is a template tag?
Second one is correct.
def viewed(self, user):
return self.viewed_episodes.filter(user=user.profile).exists() or None
I have a Django ModelForm in Google App Engine with a ChoiceField, let's say location:
class MyForm(ModelForm):
location = ChoiceField(label="Location")
class Meta:
model = MyModel
In order to dynamically add the choices for location, and not have issues with app caching, I add them after the form has initialized:
form = MyForm(request.POST, instance=my_instance)
form.fields['location'].choices = Location.all().fetch(1000)
The problem I'm having now is that when the form is initialized via the data in request.POST the choices do not yet exist and I am receiving an error stating that an invalid choice is made (since the value does not yet exist in the list of choices).
I don't like that validation is occurring when I am initializing the form instead of waiting until I call form.is_valid(). Is there any way to suppress validation during my object instantiation? Or some other way to fix this?
UPDATE: I'm pretty sure ModelFormMetaclass is causing me my grief by validating the provided instance when the form is created. Still not sure how to fix though.
Thanks!
There must be other ways to do this, but possibly the most straightforward is to add the field in the form's __init__() method:
class MyForm(ModelForm):
...
def __init__(self, *args, **kwargs):
try:
dynamic_choices = kwargs.pop('dynamic_choices')
except KeyError:
dynamic_choices = None # if normal form
super(MyForm, self).__init__(*args, **kwargs)
if dynamic_choices is not None:
self.fields['location'] = ModelChoiceField(
queryset=dynamic_choices)
class Meta:
model = MyModel
And your view would look something like:
def my_view(request):
locations = Location.objects.all() # or filter(...) or whatever
dynamic_form = MyForm(dynamic_choices=locations)
return direct_to_template(request,
'some_page.html',
{'form': dynamic_form},)
Let us know how that works for you.