i am trying to retrieve latest single data from Django model and show it in templates instead of all the data the method I trying to use in my view to achieve that
def preview(request):
readme = Personal_readme.objects.latest('create_date')
return render(request, 'preview.html',{'readme':readme})
and in my models
create_date = models.DateTimeField(default=timezone.now,editable=False)
but when I runserve and refer to a page it
TypeError at /preview/
Personal_readme' object is not iterable
it work fine when use this
readme = Personal_readme.objects.all()
but retrieve all the data in it but i want to retrieve single(one) the latest data based on create_date
I have no idea why its is show like this
I guess your template waits list of items, and when you give it one, it cause to error.
So you can change your template to handle 1 item, or give it list with 1 item like so:
def preview(request):
readme = [Personal_readme.objects.latest('create_date')]
return render(request, 'preview.html',{'readme': readme})
Related
I have this field in my model:
class PlayerDetailPage(Page):
picture = models.ForeignKey('wagtailimages.Image', null=True, on_delete=models.SET_NULL, related_name='+', help_text=_('Player profile picture.'))
And I want to create a inclusion tag, where I access different fields on this Wagtail page model. For db efficiency I use values but on the picture field I want the full query set. Not just a value in a dictionary because I need to render the image.
Right now I have this view:
PlayerDetailPage.objects.values('title', 'path' , 'slug', 'owner__age', 'owner__nationality', )
So far so good, I am pulling only the fields I need and I get a nice dictionary with one query. However for the picture field I want the full query set because it is a Wagtail picture field. It has some nice render options attached. How can I combine this in my view to get the best db efficient query?
And unfortunately direct url is not a field in the image model I guess it is a property, I tried picture__url but that resolved in:
Cannot resolve keyword 'url' into field. Choices are: collection, collection_id, created_at, file, file_hash, file_size, focal_point_height, focal_point_width, focal_point_x, focal_point_y, height, id, renditions, tagged_items, tags, title, uploaded_by_user, uploaded_by_user_id, width
My view:
#register.inclusion_tag('wdashboard/tags/player_widget.html', takes_context=True)
def player_widget(context):
qs = PlayerDetailPage.objects.values('title', 'path' , 'picture__file', 'slug', 'owner__age', 'owner__nationality', )
for ins in qs:
ins['picture'] = Image(file=ins['picture__file'])
return {'values1': qs,'request': context['request'],}
The thing you are looking for is not possible without a tricky solution IMHO. The reason is that values method runs a very well defined query only once on db and then converts results into dict. So you are never going to get original PlayerDetailPage object but a dict. For example if you have a model MyModel and you do following
x = MyModel.objects.get(id=1)
print(type(x)) # <class 'MyModel'>
But for values the case is different
x = MyModel.objects.values('id').get(id=1)
print(type(x)) # <class 'dict'>
So you lose original object and get a dict.
A little clever solution
If you have no other choice then using values, I would suggest following solution.
Build your query and also get data you need from Image model.
qs = PlayerDetailPage.objects.values('picture__name') # assume there is a name field.
Now loop over qs, initialize an Image object, (don't save it) and add it to your dictionary like this
from wagtail.images.models import Image
for ins in qs:
ins['picture'] = Image(name=ins['picture__name'])
Now you have an picture in your values qs as instance and you can use nice render options attached with it.
I have a django page that displays a list of links. Each link points to the detail page of the respective object. The link contains the pk/id of that object (something like ../5/detailObject/). The list is generated on the backend and has some filtering baked into it, e.g. only generate a link if that object has state x, etc.
Clicking on the links works, but users can still manipulate the url and pass a valid link with an incorrect state (a wrong pk/id is being handled with the get or 404 shortcut).
What is the best practice for handling this kind of scenario with django? Should that kind of filtering be placed in the object's model class instead of using function-based views as I do now?
Function based view:
If you want to restrict a set of objects to a particular user (for instance a user's orders), then you would need to set up the Order model to foreign key to the User model and then look up the order by both id and user:
views.py:
def get_order(request, id=0)
if request.method == 'GET':
try:
order = Order.objects.get(user=request.user, pk=id)
except Order.DoesNotExist:
return redirect(...)
And set up a url to handle:
url(r'^order/(?P<id>\d+)/$', views.get_order, name='get_order_by_id'),
As far as adding a slug field on the model after the fact, set up a second url:
url(r'^order/(?P<slug>[\w-]+)/$', views.get_order, name='get_order_by_slug')
And change the above view logic to first do a lookup by pk if pk is greater than 0 and then redirect back to the function using the slug from the looked up order (this assumes all looked-up records have slugs):
def get_order(request, slug='', id=0)
if request.method == 'GET':
try:
if id > 0:
order = Order.objects.get(user=request.user, pk=id)
return redirect(reverse('get_order_by_slug'), permanent=True, slug=order.slug)
order = Order.objects.get(user=request.user, slug=slug)
except Order.DoesNotExist:
return redirect(...)
You should also put unique=True on the slug field and ensure that the user is authenticated by placing the #login_required decorator on your view.
To restrict orders by a particular status, you could:
Create a set of statuses for your Order model, and then you could:
Pass a value for a kwarg in the view when you filter, or
Create a custom manager on the Order model
There are several ways you could create your statuses:
as a set of choices on the Order model
use the SmartChoices library
as a database field
If you create choices on the Order model, it could be something like this:
class Order(models.model):
STATUSES = (
('PLCD', 'Placed'),
('INTR', 'In Transit'),
('DLVR', 'Delivered')
)
status = models.CharField(max_length=4, default='', choices=STATUSES)
An acquaintance who is a very seasoned Django professional told me about the SmartChoices library. I have not used it yet but would like to try it at some point. The database field option would be my least preferred way of doing this because that seems to me like moving programming variables into the database; however, it would work.
I'm using django-filter which is working great but I am having a problem filtering my drop down list of choices (which is based on a model) by the current user. It's a fairly basic and common scenario where you have a child table which has a many to one relationship to a parent table. I want to filter the table of child records by selecting a parent. This is all fairly easy, standard stuff. The fly in ointment is when the parent records are created by different users and you only want to show the parent records in the drop down list that belongs to the current user.
Here is my code from filters.py
import django_filters
from django import forms
from .models import Project, Task
from django_currentuser.middleware import get_current_user, get_current_authenticated_user
class MasterListFilter(django_filters.FilterSet):
project = django_filters.ModelChoiceFilter(
label='Projects',
name='project_fkey',
queryset=Project.objects.filter(deleted__isnull=True, user_fkey=3).distinct('code')
)
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 bit works fine:
#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 filters my main list so that only records that have a master flag set, have not been deleted and belong to the current user are shown. This is exactly what I want.
This following bit also works and gives me the filtered drop down list that I am looking for because I have hardcoded 3 as the user.id
queryset=Project.objects.filter(deleted__isnull=True, user_fkey=3).distinct('code'),
Obviously I don't want to have a hardcoded id. I need to get the value of the current user. Following the same logic used for filtering the main table I end up with this.
class MasterListFilter(django_filters.FilterSet):
**user = get_current_user()**
project = django_filters.ModelChoiceFilter(
label='Projects',
name='project_fkey',
queryset=Project.objects.filter(deleted__isnull=True, user_fkey=**user.id**).distinct('code')
)
However this is unreliable as sometimes it shows the correct list and sometimes it doesn't. For example if I login and it's not showing the list (ie it shows just '---------') and then I restart my apache2 service, it starts to work again, then at some point it drops out again. Clearly this is not a long term solution.
So how do I reliably get the current user into my filter.py so that I can use it to filter my drop down filter list.
Thanks in advance and happy coding.
EDIT:
So following Wiesion's suggestion I changed my code as suggested but I still get a None Type Error saying that user has no attribute ID. BAsically it seems I'm not getting the current user. So going back to the docs and trying to merge their suggestion with Wiesion (whose explanation makes total sense - Thanks Wiesion) I came up with the following:
def Projects(request):
if request is None:
return Project.objects.none()
return lambda req: Project.objects.filter(deleted__isnull=True, user_fkey=req.user.id)
class MasterListFilter(django_filters.FilterSet):
project = django_filters.ModelChoiceFilter(
label='Projects',
name='project_fkey',
queryset=Projects
)
class Meta:
model = Task
fields = ['project']
This kind of works in theory but gives me nothing in the drop down list because
if request is None:
is returning True and therefore giving me an empty list.
So...can anyone see where I'm going wrong which is preventing me from accessing the request? Clearly the second portion of code is working based on qs that is passed from my view so maybe I need to pass in something else too? My view.py code is below:
def masterlist(request, page='0'):
#Check to see if we have clicked a button inside the form
if request.method == 'POST':
return redirect ('tasks:tasklist')
else:
# Pre-filtering of user and Master = True etc is done in the MasterListFilter in filters.py
# Then we compile the list for Filtering by.
f = MasterListFilter(request.GET, queryset=Task.objects.all())
# Then we apply the complete list to the table, configure it and then render it.
mastertable = MasterTable(f.qs)
if int(page) > 0:
RequestConfig(request, paginate={'page': page, 'per_page': 10}).configure(mastertable)
else:
RequestConfig(request, paginate={'page': 1, 'per_page': 10}).configure(mastertable)
return render (request,'tasks/masterlist.html',{'mastertable': mastertable, 'filter': f})
Thanks.
From the docs
The queryset argument also supports callable behavior. If a callable
is passed, it will be invoked with Filterset.request as its only
argument. This allows you to easily filter by properties on the
request object without having to override the FilterSet.__init__.
This is not tested at all, but i think something along these lines this is what you need:
class MasterListFilter(django_filters.FilterSet):
project = django_filters.ModelChoiceFilter(
label='Projects',
name='project_fkey',
queryset=lambda req: Project.objects.filter(
deleted__isnull=True, user_fkey=req.user.id).distinct('code'),
)
class Meta:
model = Task
fields = ['project']
Also if it's depending from webserver restarts - did you check caching issues? (In case, django-debug-toolbar gives great insights about that)
EDIT
The unpredictable behaviour most probably happens because you are retrieving the user within the class MasterListFilter definition, so get_current_user() is executed at class loading time, not during an actual request and all subsequent calls to qs will retrieve that query. Generally everything request-related should never be in a class definition, but in a method/lambda. So a lambda which receives the request argument and creates the query only then should exactly cover what you need.
EDIT 2
Regarding your edit, the following code has some issues:
def Projects(request):
if request is None:
return Project.objects.none()
return lambda req: Project.objects.filter(deleted__isnull=True, user_fkey=req.user.id)
This either returns an empty object manager, or a callable - but the method Project itself is already a callable, so your ModelChoiceFilter will receive only an object manager when the request object is None, otherwise a lambda, but it is expecting to receive an object manager - it can't iterate over a lambda so it should give you some is not iterable error. So basically you could try:
def project_qs(request):
# you could add some logging here to see what the arguments look like
if not request or not 'user' in request:
return Project.objects.none()
return Project.objects.filter(deleted__isnull=True, user_fkey=request.user.id)
# ...
queryset=project_qs
# ...
As stated in the following thread, you have to pass the request to the filter instance in the view: Customize queryset in django-filter ModelChoiceFilter (select) and ModelMultipleChoiceFilter (multi-select) menus based on request
ex:
myFilter = ReportFilter(request.GET, request=request, queryset=reports)
I have large table of data (~30 Mb) that I converted into into a model in Django. Now I want to have access to that data through a REST API.
I've successfully installed the Django REST framework, but I'm looking for a way to automatically create a URL for each field in my model. My model has about 100 fields, and each field has about 100,000 entries.
If my model is named Sample,
models.py
class Sample(models.Model):
index = models.IntegerField(primary_key=True)
year = models.IntegerField(blank=True, null=True)
name = models.TextField(blank=True, null=True)
...97 more fields...
then I can access the whole model using Django REST framework like this:
urls.py
class SampleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Sample
fields = ( **100 fields**)
class SampleViewSet(viewsets.ModelViewSet):
queryset = Sample.objects.all()
serializer_class = SampleSerializer
router = routers.DefaultRouter()
router.register(r'sample', SampleViewSet)
But of course my browser can't load all of that data in a reasonable amount of time. I could manually make a different class and URL for each field, but there must be a better way... I want to be able to go to my_site.com/sample/year (for example) and have it list all of the years in JSON format, or my_site.com/sample/name and list all the names, etc.
Please help me figure out how to do this, thanks!
You might be able to do that using a custom viewset route.
You have this:
class ModelViewSet(ModelViewSet):
#list_route()
def sample_field(self, request):
desired_field = request.data.get('field', None)
if not desired_field:
return response # pseudocode
values = Model.objects.all().values_list(desired_field, flat=True)
# serialize this for returning the response
return Response(json.dumps(values)) # this is an example, you might want to do something mode involved
You will be able to get this from the url:
/api/model/sample_field/?field=foo
This extra method on the viewset will create a new endpoint under the samples endpoint. Since it's a list_route, you can reach it using /sample_field.
So following your code, it would be:
mysite.com/sample/sample_field/?field='year'
for example.
There are many interesting details in your question, but with this sample I think you might able to achieve what you want.
Try to use pagination. You can do it in almost the same way as in you question. Pagination in django lets you divide the results into pages. You don't have to display all the entries in the same page. I think this is the best option for you.
Refer django documentation on pagination:
Pagination in django
I have the following model in a project:
class CarAssignment(models.Model):
leg = models.ForeignKey(Leg, null=True, blank=True)
driver = models.ForeignKey(Driver, null=True, blank=True)
riders = models.ManyToManyField(Rider, null=True, blank=True)
I'm trying to create a page with a table where an admin user can edit the driver and riders items for all of the car assignments in a specific group. I can't use a formset because I also need to add data from another model, and because the choices in each list come from a different subset of riders and drivers, those that belong to a specific group. Driver is a select list and Riders is a multiselect list.
I have successfully built the page and table to represent the data, with correctly working drop-down lists. However, I can't figure out how to save the items. Here's a specific problem scenario:
for row 1 in the table (representing CarAssignment object #1), I pick a new driver from the list in the select dropdown. I'm assigning custom name tags in the html to identify them, as follows:
<option selected name="select.driver.{{ car_assignment.id }}">{{ driver }}</option>
Then in the view, I'm trying to see if it matches anything, as follows:
for car_assignment in CarAssignment.objects.filter(leg__in=legs):
driver_tag = "select.driver." + str(car_assignment.id)
if driver_tag in request.POST:
car_assignment.driver = driver
car_assignment.save()
The problem is that when it finds a matching driver tag, all it returns is a string of the First Name and Last Name. I can't do the car_assignment.driver = driver because it's trying to equate a driver object to a string.
I'm not sure how to do this. I guess I could parse out the first and last names and try to match them against the Driver model to get the Driver objects I need, but that seems inefficient and possibly error-prone.
Any help is appreciated (I'm a programming and Django newbie). Thanks.
I'm not sure where your that driver field is coming from, but if it's a String, you could then do another query to get the driver object like so:
for car_assignment in CarAssignment.objects.filter(leg__in=legs):
driver_tag = "select.driver." + str(car_assignment.id)
if driver_tag in request.POST:
# Get the driver object
driver = Driver.objects.filter(name=driver_name)[0]
car_assignment.driver = driver
car_assignment.save()
I'd also highly recommend that you read the Django tutorial Working with forms. The logic that you're writing in the view should be moved to a form object. Your view can then instantiate the form and pass the post data. The form can then be validated and will handle saving your new objects. This is the best way to do this.
The updated flow for your view would be simplified to something like this:
def my_view(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
form.save()
# Do something here like redirect the user
# to acknowledge that the form was submitted successfully.
else:
form = MyForm()
return render_to_response('form.html', {
'form': form,
})
By passing the form to your template you can generate the form doing nothing but this:
{{ form.as_ul }}