i am trying to call a class based view and i am able to do it, but for some reason i am not getting the context of the new class that i am calling
class ShowAppsView(LoginRequiredMixin, CurrentUserIdMixin, TemplateView):
template_name = "accounts/thing.html"
#method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(ShowAppsView, self).dispatch(*args, **kwargs)
def get(self, request, username, **kwargs):
u = get_object_or_404(User, pk=self.current_user_id(request))
if u.username == username:
cities_list=City.objects.filter(user_id__exact=self.current_user_id(request)).order_by('-kms')
allcategories = Category.objects.all()
allcities = City.objects.all()
rating_list = Rating.objects.filter(user=u)
totalMiles = 0
for city in cities_list:
totalMiles = totalMiles + city.kms
return self.render_to_response({'totalMiles': totalMiles , 'cities_list':cities_list,'rating_list':rating_list,'allcities' : allcities, 'allcategories':allcategories})
class ManageAppView(LoginRequiredMixin, CheckTokenMixin, CurrentUserIdMixin,TemplateView):
template_name = "accounts/thing.html"
def compute_context(self, request, username):
#some logic here
if u.username == username:
if request.GET.get('action') == 'delete':
#some logic here and then:
ShowAppsView.as_view()(request,username)
What am i doing wrong guys?
Instead of
ShowAppsView.as_view()(self.request)
I had to do this
return ShowAppsView.as_view()(self.request)
Things get more complicated when you start using multiple inheritance in python so you could easily be trampling your context with that from an inherited mixin.
You don't quite say which context you are getting and which one you want (you're not defining a new context), so it's difficult to completely diagnose, but try rearranging the order of your mixins;
class ShowAppsView(LoginRequiredMixin, CurrentUserIdMixin, TemplateView):
this implies that LoginRequiredMixin will be the first class to inherit from, and so it will take precedence over the others if it has the attribute you're looking for - if it hasn't then python will look in CurrentUserIdMixin and so on.
If you want to be really sure that you get the context that you're after, you could add an override like
def get_context(self, request):
super(<my desired context mixin>), self).get_context(request)
to ensure that the context you get is the one from the mixin that you want.
* Edit *
I don't know where you've found compute_context but it's not a django attribute so will only get called from ShowAppsView.get() and never in ManageAppView.
Related
I'm new to Django and I'm having a hard time understanding forms when the data to choose from are not taken from the database nor user input that they're generated on the go.
I currently have a template with a single ChoiceField. The data inside this field aren't fixed and they're calculated on the go once the page is requested. To calculate it I need the username of the User who is logged in. Basically, the calculation returns a list of lists in the form of ((title, id),(title,id),(title,id)), etc. that I need to put into the ChoiceField to make the User choose from one of the options.
Now, I'm not understanding how to pass the calculated list of lists to the form. I've tried to add the calculations inside the form as below but it is clearly the wrong way.
The main issue is that, to calculate my list of lists, I need the request value, and I don't know how to access it from the form.
Another idea was to add the generate_selection function inside the init but then I don't know how to pass main_playlist to being able to add it to ChoiceField
Below my not working forms.py
forms.py
class ChoosePlaylistForm(forms.Form):
playlists = forms.ChoiceField(choices=HERE_SHOULD_GO_main_playlist)
def generate_selection(self):
sp_auth, cache_handler = spotify_oauth2(self.request)
spotify = spotipy.Spotify(oauth_manager=sp_auth)
user_playlists = spotify.current_user_playlists(limit=10)
main_playlist = []
for playlists in user_playlists["items"]:
playlists_list = []
playlists_list.append(playlists['name'])
playlists_list.append(playlists['id'])
main_playlist.append(playlists_list)
return main_playlist
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(ChoosePlaylistForm, self).__init__(*args, **kwargs)
class Meta:
model = User
fields = ('playlists',)
The views should be something like below so I'm able to pass the request
views.py
form = ChoosePlaylistForm(request=request)
Maybe overriding the field choices in the form constructor would work:
class ChoosePlaylistForm(forms.Form):
playlists = forms.ChoiceField(choices=())
class Meta:
model = User
fields = ('playlists',)
def __init__(self, *args, request=None, **kwargs):
super(ChoosePlaylistForm, self).__init__(*args, **kwargs)
self.request = request
self.fields['playlists'].choices = self.generate_selection()
def generate_selection(self):
sp_auth, cache_handler = spotify_oauth2(self.request)
spotify = spotipy.Spotify(oauth_manager=sp_auth)
user_playlists = spotify.current_user_playlists(limit=10)
choices = []
for playlist in user_playlists["items"]:
playlist_choice = (playlist["name"], playlist["id"])
choices.append(playlist_choice)
return choices
I need to pass a parameter in the URL to the Django Admin add view, so that when I type the URL: http://localhost:8000/admin/myapp/car/add?brand_id=1, the add_view reads the brand_id parameter. I want to use this so that I can set a default value for the brand attribute of Car.
def get_form(self, request, obj=None, **kwargs):
form = super(CarAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['brand'].initial = <<GET['brand_id']>>
return form
Use case: I want this because in my BrandsAdmin, I have added a "+" button for each brand, that should add a Car with that Brand as FK.
I've tried getting it from request in get_form, but when that code is executed, Django has already changed my URL as I guess it doesn't understand it as a "legal" parameter.
Thanks a lot!
Using django 3 i did it overriding get_form in CarAdmin.py like you did, and its working for me, maybe the trick is in Brand.py:
Brand.py
readonly_fields = ('get_add_link',)
def get_add_link(self, obj):
url = f"{reverse('admin:myapp_car_add')}?brand={self.id}"
return format_html(f"<a href='{url}'><i class='fas fa-plus'></i></a>")
CarAdmin.py
def get_form(self, request, obj=None, **kwargs):
form = super(CarAdmin, self).get_form(request, obj, **kwargs)
brand_id = request.GET.get('brand')
if brand_id and len(brand_id) > 0:
form.base_fields['brand'].initial = brand_id
You can find a full explanation here, but shortly:
You can access query parameters directly from the view, the request object has a method. I suppose it is a GET request, so an example for your implementation would be:
request.GET.getlist("brand_id")
or
request.GET.get("brand_id")
Mainly, for what I wanted to do, it's as easy as two steps.
First, add a column in list_display to show the link to the add_view:
Brand.py
#admin.display(description='Link', ordering='url')
def get_add_link(self):
url = f"{reverse('admin:myapp_car_add')}?brand={self.id}"
return format_html(f"<a href='{url}'><i class='fas fa-plus'></i></a>")
Note that I add the URL as the reverse of admin:<app>_<model>_<action> and pass the brand ID as parameter.
CarAdmin.py
def get_changeform_initial_data(self, request):
brand_id = request.GET.get('brand')
return {'brand': brand_id}
By adding this method in the CarAdmin class, I am able to set the brand as the default value.
I did not have to do anything with the Model. The only change needed was in the ModelAdmin:
def get_changeform_initial_data(self, request):
brand = None
brand_id = request.GET.get('brand')
if (brand_id):
brand = Brand.objects.get(id=brand_id)
return {'brand': brand}
Docs link here: https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_changeform_initial_data
Is the any solution to get django's user_full_name as a initial value for form? My idea was to display a django's form on the end of shopping to finish a order. I want also do put into a form total value, but this is for later.
I did something like this:
user_dane = request.user.get_full_name
koszyk = request.session.get('koszyk', [])
produkty = list(Produkt.objects.filter(pk__in=koszyk))
suma_cen = Produkt.objects.filter(pk__in=koszyk).aggregate(suma=Sum('cena'))
suma_wszystkich_cen = suma_cen['suma']
form=ZamowienieForm(initial={'imie_nazwisko':user_dane, 'kwota_do_zaplaty':suma_wszystkich_cen})
but this is working only when request.method is POST.
if request.method =='POST':
form = ZamowienieForm()
According to documentation I shouldn't initial a empty form with POST... Is there any chance to have a user full name into a form?
Here is the form class:
class ZamowienieForm(forms.ModelForm):
class Meta:
model = Zamowienie
fields = ('imie_nazwisko', 'kwota_do_zaplaty', 'miejscowosc',
'ulica','numer_domu', 'numer_mieszkania', 'kod_pocztowy',)
class NewMeta:
readonly = ('imie_nazwisko','kwota_do_zaplaty',)
Maybe try something like this inside ZamowienieForm class
def __init__(self, *args, **kwargs):
super(ZamowienieForm, self).__init__(*args, **kwargs)
self.fields['imie_nazwisko'] = self.initial.get('imie_nazwisko')
self.fields['kwota_do_zaplaty'] = self.initial.get('kwota_do_zaplaty')
Although I don't understand why "initial" is not working out of the box
In this case, you only need to initialize your form once, and not inside a conditional check if the request is a GET or POST:
def your_view(request):
form = ZamowienieForm(
request.POST or None,
initial={'imie_nazwisko': request.user.get_full_name(),
'kwota_do_zaplaty': suma_wszystkich_cen}
)
if request.method == 'POST' and form.is_valid():
# do whatever
This way you are always passing in the initial value, and if request.method == 'GET', then None is passed as the first positional argument to the form.
Also, user.get_full_name is an instance method, not a property, so using request.user.get_full_name only returns the bound method, not the actual value. You have have to call the function using ()
Finally, this will only work for users that are authenticated. The anonymous user object in Django won't return any user-specific information.
Here is my tastypie code snippet.
I have a Resource and in post_list method , an instance of Mysample is getting created there.
I want to call a method of Mysample Instance , Please help me how to do that,
please find the comment in code where I need to call the method of Mysample instance
class MysampleResource(ModelResource):
intfeild1 = fields.IntegerField('intfeild1_id', null=True)
intfeild2 = fields.IntegerField('intfeild1_id')
class Meta:
always_return_data = True
queryset = Mysample.objects.all()
allowed_methods = ['get','post','put','delete',]
authentication = SessionAuthentication()
authorization = MysampleAuthorization()
def post_list(self, request, **kwargs):
result = super(MysampleResource, self).post_list(request, **kwargs)
#here I want to call a method of Mysample Instance.
return result
Please help me , I'm begginer, so could you please give suggestion on which method to override and where should I need to do that.
You just need to add your method in your resource:
def test_method(self,param*):
#Do your stuff
return result
and within post_list you can call it like:
self.test_method(param*)
Note: The method declaration include 2 params but in python "self" is passed on as an implicit param so that when you call your method you don't pass on the self object.
= could be more than just one parameter in that case use "," in order to separate them.
If we apply all the previous concepts your code should look like:
class MysampleResource(ModelResource):
intfeild1 = fields.IntegerField('intfeild1_id', null=True)
intfeild2 = fields.IntegerField('intfeild1_id')
class Meta:
always_return_data = True
queryset = Mysample.objects.all()
allowed_methods = ['get','post','put','delete',]
authentication = SessionAuthentication()
authorization = MysampleAuthorization()
def post_list(self, request, **kwargs):
result = super(MysampleResource, self).post_list(request, **kwargs)
#Let's say that you want to pass resquest as your param to your method
method_result=self.test_method(request)
return result
def test_method(self,request):
#Do your stuff
return result
I don't know how to make one customization in my Django admin panel.
For example I have table test and another table testinfo. I know how to make admin.TabularInline of testinfo table in test table. But how to check, for example, if id of test table is bigger than 3, to show TabularInline, if not to not show?
ModelAdmin has a method called get_inline_instances() that can be used to achieve this effect.
class TestAdmin(admin.ModelAdmin):
def get_inline_instances(self, request, obj=None):
if obj.id > 3:
self.inlines = [TestInfoInline, ]
else:
self.inlines = []
return super(TestAdmin, self).get_inline_instances(request, obj)
Second example - the effect remains exactly the same:
class TestAdmin(admin.ModelAdmin):
inlines_foo = []
inlines_bar = [TestInfoInline, ]
def get_inline_instances(self, request, obj=None):
self.inlines = self.inlines_foo if obj.id <= 3 else self.inlines_bar
return super(TestAdmin, self).get_inline_instances(request, obj)
Well I think your problem is related to the issue discussed here Misleading documentation in ModelAdmin.get_inline_instances. So essentially your code should be changed to something like...
# Assuming you have a TestInfoInline inline that inherits from a BaseModelAdmin defined
# similarly to below.
class TestInfoInline(admin.StackedInline):
# Relevant stuff here...
...
class TestAdmin(admin.ModelAdmin):
def get_inline_instances(self, request, obj=None):
inlines = []
if obj.id > 3:
for inline_class in self.inlines:
# Instanciate inline object
inline = inline_class(self.model, self.admin_site)
inlines.append(inline)
return inlines
Hope this helps someone...