Safely store data from GET request - Django - python

Alright,
Let's say we need to create a website with Django where people can book a lodge for the weekends.
We add a search form on the homepage where people can fill in the check-in and check-out date
to filter for all available lodges.
We use a generic Listview to create an overview of all the lodges and we overwrite the queryset to grab the search parameters from the GET request to create a filtered view.
views.py
class ListingsView(ListView):
"""Return all listings"""
model = Listing
template_name = 'orders/listings.html'
def get_queryset(self):
"""
Visitors can either visit the page with- or without a search query
appended to the url. They can either use the form to perform a search
or supply an url with the appropriate parameters.
"""
# Get the start and end dates from the url
check_in = self.request.GET.get('check_in')
check_out = self.request.GET.get('check_out')
queryset = Calendar.objects.filter(
date__gte=check_in,
date__lt=check_out,
is_available=True
)
return queryset
Now this code is simplified for readability, but what I would like to do, is store the check-in and check-out date people are searching for.
Updated views.py
class ListingsView(ListView):
"""Return all listings"""
model = Listing
template_name = 'orders/listings.html'
def get_queryset(self):
"""
Visitors can either visit the page with- or without a search query
appended to the url. They can either use the form to perform a search
or supply an url with the appropriate parameters.
"""
# Get the start and end dates from the url
check_in = self.request.GET.get('check_in')
check_out = self.request.GET.get('check_out')
queryset = Calendar.objects.filter(
date__gte=check_in,
date__lt=check_out,
is_available=True
)
Statistics.objects.create(
check_in=check_in,
check_out=check_out
)
return queryset
We created a "Statistics" model to store all dates people are looking for.
We essentially add data to a model by using a GET request and I'm wondering if this is the right way of doing things? Aren't we creating any vulnerabilities?
The search form uses hidden text inputs, so there's always the possibility of not knowing what data is coming in. Is cleaning or checking the datatype from these input enough, or will this always be in string format?
Any ideas?
Greetz,

Related

Django model manager queryset not updating until server restarts

I have a program that lets users upload data files and lookup tables (both which are ID'd to a specific company) and map them together. One page lets users choose which company they want to map data for by looking at which companies have both data files and lookup tables, which I use a queryset/model manager for. The problem is if I load a new data file and hierarchy the queryset doesn't pick them up until the server restarts. The queryset returns all the companies that have a data file and hierarchies at the time the server starts, but not anything that's added afterwards. I think this must be because the queryset is defined at startup, but I'm not sure. Is there a way to work around this?
forms.py
class CompanySelectionForm(forms.Form):
companies = RawData.objects.get_companyNames(source="inRDandH")
companiesTuple = makeTuple(companies)
print(companiesTuple)
company = forms.ChoiceField(widget=forms.Select(attrs={'class': 'form-select'}), choices=companiesTuple)
managers.py
class RawDataManager(models.Manager):
def get_queryset(self):
return RawDataQuerySet(self.model, using=self._db)
def get_companyNames(self, source):
return self.get_queryset().get_companyNames(source)
class RawDataQuerySet(models.QuerySet):
def get_companyNames(self, source):
if (source == 'inRDandH'):
distinct_companiesRD = self.filter(fileType=0).values_list('companyName', flat=True).distinct()
distinct_companiesH = self.filter(fileType=1).values_list('companyName', flat=True).distinct()
distinct_companies = set(distinct_companiesRD).intersection(set(distinct_companiesH))
else:
distinct_companies = self.values_list('companyName', flat=True).distinct()
return distinct_companies
The problem is that this code runs only once, when the code is initialised on server start, because it is part of your form class definition:
companies = RawData.objects.get_companyNames(source="inRDandH")
The solution is to make choices a callable, which is run every time the form is instantiated. define that field dynamically, in the __init__ method of the form:
def get_companies_tuple():
companies = RawData.objects.get_companyNames(source="inRDandH")
return makeTuple(companies)
class CompanySelectionForm(forms.Form):
company = forms.ChoiceField(
widget=forms.Select(attrs={'class': 'form-select'}),
choices=get_companies_tuple
)
This will now fetch the data from the database every time the form is initialised, rather than only once during startup.

How to sort queryset output in view django?

I have these two models :
class Home(db_interface.Entity):
patient = models.ForeignKey(Patient, help_text='Patient')
sode = models.ForeignKey(Sode, help_text='sode')
class Sode(db_interface.Entity):
start_date = models.DateField(validators=[validate_date_range], null=True, help_text="Start Date")
path = models.ForeignKey('Path', null=True, blank=True)
help_text="Path")
and my view is inherited from a ListView of Django .To return a queryset I override get_queryset() method :
def get_queryset(self):
instance = self.get_instance()
if instance:
return Sode.objects.filter(patient=instance).select_related('path').prefetch_related(
'home_set')
return []
to list data in my template I use a for loop :
{% for h in sode.home_set.all %}
data is displayed in lists perfectly, but what I want to do now is to filter the list (not the standard filter approach) I mean the items in the list will be modified depending of the status of some items .
I tried to write a custom filter so that the every time my template is loaded I have data in the list are shown as I want. But I recognized that in my filter I used objects from database which must be in the view to separate presentation code from data logic, so filtering models musn't be in a filter
I ended up by moving the logic I wrote in the custom filter to a function in my model's ListView
def sort_homes_per_sode(self,sode):
homes = sode.get_queryset()
#some logic here
return list_homes_filtred_depending_on_the_type_of_some_homes_of_sode
I don't know if I'm in a good way, and still don't know if the function is usefull or not and how to show data in template and associate every filtered list of homes to the corresponding sode

How to consult data with django forms?

I'm playing with Django and I have a situation where I have a form and the user define a two dates, like when we need to book a flight, departure date and return date. In my forms.py I have a Form class with two fields for dates
class MyForm(forms.Form):
dateOne = forms.DateTimeField()
dateTwo = forms.DateTimeField()
I need to retrieve objects from a model by passing the dates defined by the user. In my template I'm using get action, on form html tag, but I'm stuck on how I can make this consult and bring the objects to the template.
If I need create a logic on my views.py or in my forms.py. Does anyone know some thing to me start this task?
You're going to want to create an additional view that accepts an AJAX request and sends back a JSON response with the objects you're looking for. So if the user enters two dates you POST/GET those dates to the backend and then your view looks something like this:
class SomeView(View):
def get(self, request, *args, **kwargs):
object_list = YourObject.objects.filter(date__range=[start_date, end_date])
# Do something to your object_list to make it a JSON serializable list
return JsonResponse({'object_list': object_list})

Dynamically check if a slug exists

On a legacy app, I need to check if a URL exists, and if it does not, to redirect it to another location. The problem is that I need to check if that url is present in a set of values, in the urls file and I'm not clear on how best to do that.
For example, both projects and cities are sharing the same url pattern. e.g. /projects/london and /projects/my-project-name.
I want to first check if the slug matches a city, and if it does not to then return the project view (cities cannot match project names).
My urls are currently structured as follows:
url(r'^projects/(?P<project-name>[-\w]+)', get_project, name='project-view'),
url(r'^projects/.*', get_city, name='city-view'),
I know this is very messy, and a bad overall pattern but unfortunately it's not something that can be changed at the moment. So my goal is to figure out if I can first check if the project-name could be a city, and if it is, to redirect onto that view without falling into a redirect loop.
I wondered if I could do something like this:
url(r'^projects/(?P<city>london|paris|new-york)/', get_city, name='city-view'),
where london|paris|new-york are generated dynamically
You can dynamically generate a url with all of the city names, but the url will be cached once django accesses it the first time, so in order to modify the url regex, you'd have to restart the django process. If that's fine for your purposes, you can generate the url like this:
url(r'^projects/(?P<city>{})/$'.format(city_slugs.join('|')),
get_city, name='city-view')
But, it would probably be better to create a view routing method that implements the logic to send requests to their appropriate view:
# urls.py
# ...
url(r'^projects/(?P<slug>[-\w]+)/$',
project_city_router, name='project-city-router'),
# ...
# views.py
def is_a_city(slug):
# If they're in the database, something like:
# return City.objects.filter(slug=slug).exists()
return slug in ['london', 'paris', 'new-york', '...']
def project_city_router(request, slug=None):
if not slug:
# /projects/
return render(request, 'my/template.html', {'foo': 'bar'})
elif is_a_city(slug):
# /projects/<city>/
return get_city(request, city=slug)
else:
# /projects/<project-name/
return get_project(request, project_name=slug)
With this router, if the slug argument is a project or city, it returns the result of the get_project or get_city view itself.
This also allows for your list of cities to be checked dynamically against a database, or file.

Inline-like solution for Django Admin where Admin contains ForeignKey to other model

I have several Customers who book Appointments. Each Appointment has exactly one customer, though a customer can be booked for multiple appointments occurring at different times.
class Customer(model.Model):
def __unicode__(self):
return u'%s' % (self.name,)
name = models.CharField(max_length=30)
# and about ten other fields I'd like to see from the admin view.
class Appointment(models.Model):
datetime = models.DateTimeField()
customer = models.ForeignKey("Customer")
class Meta:
ordering = ('datetime',)
Now when an admin goes to browse through the schedule by looking at the Appointments (ordered by time) in the admin, sometimes they want to see information about the customer who has a certain appointment. Right now, they'd have to remember the customer's name, navigate from the Appointment to the Customer admin page, find the remembered Customer, and only then could browse their information.
Ideally something like an admin inline would be great. However, I can only seem to make a CustomerInline on the Appointment admin page if Customer had a ForeignKey("Appointment"). (Django specifically gives me an error saying Customer has no ForeignKey to Appointment). Does anyone know of a similar functionality, but when Appointment has a ForeignKey('Customer')?
Note: I simplified the models; the actual Customer field currently has about ~10 fields besides the name (some free text), so it would be impractical to put all the information in the __unicode__.
There is no easy way to do this with django. The inlines are designed to follow relationships backwards.
Potentially the best substitute would be to provide a link to the user object. In the list view this is pretty trivial:
Add a method to your appointment model like:
def customer_admin_link(self):
return 'Customer' % reverse('admin:app_label_customer_change %s') % self.id
customer_admin_link.allow_tags = True
customer_admin_link.short_description = 'Customer'
Then in your ModelAdmin add:
list_display = (..., 'customer_admin_link', ...)
Another solution to get exactly what you're looking for at the cost of being a bit more complex would be to define a custom admin template. If you do that you can basically do anything. Here is a guide I've used before to explain:
http://www.unessa.net/en/hoyci/2006/12/custom-admin-templates/
Basically copy the change form from the django source and add code to display the customer information.
Completing #John's answer from above - define what you would like to see on the your changelist:
return '%s' % (
reverse('admin:applabel_customer_change', (self.customer.id,)),
self.customer.name # add more stuff here
)
And to add this to the change form, see: Add custom html between two model fields in Django admin's change_form
In the ModelAdmin class for your Appointments, you should declare the following method:
class MySuperModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if obj:
# create your own model admin instance here, because you will have the Customer's
# id so you know which instance to fetch
# something like the following
inline_instance = MyModelAdminInline(self.model, self.admin_site)
self.inline_instances = [inline_instance]
return super(MySuperModelAdmin, self).get_form(request, obj, **kwargs)
For more information, browser the source for that function to give you an idea of what you will have access to.
https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L423
There is a library you can use it.
https://github.com/daniyalzade/django_reverse_admin
But if you want to use link to object in showing table you can like this code:
def customer_link(self, obj):
if obj.customer:
reverse_link = 'admin:%s_%s_change' % (
obj.customer._meta.app_label, obj.customer._meta.model_name)
link = reverse(reverse_link, args=[obj.customer.id])
return format_html('More detail' % link)
return format_html('<span >-</span>')
customer_link.allow_tags = True
customer_link.short_description = 'Customer Info'
And in list_display:
list_display = (...,customer_link,...)

Categories

Resources