#StackBounty: #django #nginx #gunicorn Multiple Django Project + Nginx on subpath

Bounty: 50

I am trying to run multiple dashboards written in Django to run on my server, but am not getting it up and running. Followed this digital ocean tutorial and modified it according to this SO answer. Now everything is up and running and but when am pointing to my URL, it shows Nginx welcome page http://ipaddr/first_dashboard

Below is the gunicorn_fdab.socket file :

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn_fdab.sock

[Install]
WantedBy=sockets.target

Below is gunicorn_fdab.service file :

[Unit]
Description=gunicorn daemon for fdab
Requires= gunicorn_fdab.socket
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/opt/fdab
ExecStart=/opt/anaconda/envs/fdab/bin/gunicorn 
          --access-logfile - 
          --workers 3 
          --bind unix:/run/gunicorn_fdab.sock 
          fdab.wsgi:application

[Install]
WantedBy=multi-user.target

Now this is my Nginx conf file :

server {
    listen 80;
    server_name 111.11.11.111;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /opt/fdab/fdab;
    }

    location /fdab {
        include proxy_params;
        rewrite /fdab(.*) $1;
        proxy_pass http://unix:/run/gunicorn_fdab.sock;
    }
}

Am not able to understand where am doing it wrong.

If am doing curl --unix-socket /run/gunicorn_fdab.sock localhost , it just returning nothing.

(base) root@virtualserver01:~# curl --unix-socket /run/gunicorn_fdab.sock localhost
(base) root@virtualserver01:~# 

Project is stored at /opt/fdab.

Additional information:

Basically, my project structure for both the project is like this :

/opt/fdab
    /fdab
    /fdab_dashboard


/opt/pdab
    /pdab
    /pdab_dashboard

The structure for the project is like this because I intend to have multiple apps in fbad and fdab2(second project name.

EDIT

Updated conf file for Nginx :

server {
    listen 80;
    server_name 111.11.11.111;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /opt/fdab/fdab;
    }

    location /fdab {
        include proxy_params;
        rewrite /fdab/(.*) /$1 break;
        proxy_pass http://unix:/run/gunicorn_fbad.sock;
    }


    location /pdab/static/ {
        alias /opt/pdab/pdab/static/;
    }

    location /pdab {
        include proxy_params;
        rewrite /pdab/(.*) /$1 break;
        proxy_pass http://unix:/run/gunicorn_pdab.sock;
    }

}

Now I have added FORCE_SCRIPT_NAME = '/exampleproject' in both the project.

Now what’s happening is that, if am typing in, http://<ipaddr>/fdab/fdab_dashboard it’s working fine, but if am typing in http://<ipaddr>/fdab/ or http://<ipaddr>/pdab/, am getting redirected to http://<ipaddr>/fdab_dashboard and http://<ipaddr>/pdab_dashboard , this is not what is required and moreover, http://<ipaddr>/fdab_dashboard seems to be working properly. But the fdab part of the url is missing, once I get into the app after logging in, the url seems fine, maybe because of the FORCE_SCRIPT_NAME = '/fdab' , but the url http://<ipaddr>/pdab_dashboard gives me 404 error page.


Get this bounty!!!

#StackBounty: #python #django #django-models #django-views #django-channels New chat message notification Django Channels

Bounty: 200

I’ve got Django Channels 2.1.2 set up in my Django app by following a tutorial and now need to set up a notification system for new messages. I want to do this in the simplest way possible (ideally using native Django features if possible…etc Django templating).

I’ve looked around the internet but there isn’t a clear tutorial/explanation anywhere for doing this with Django Channels.

One answer on here said

For notifications you only need two models: User and Notification. On
connect set the scope to the currently authenticated user. Set up a
post_save signal on your Notification model to trigger a consumer
method to message the notification object’s user. –

I am struggling to wrap my head around what this would look like, I already have a User model but no Notification one.

Would I have a signals.py in my chat app which looked something like

@receiver(post_save, sender=User)
def create_notification(sender, instance, created, **kwargs):
    if created:
        Notification.objects.create(user=instance)

What would the front end look like? This is obviously all in-app and not via emails.

Would I save any instances of the Notification model (generated by post_save signals.py) to my database and then render out that figure using Django templating in the top corner of the webpage for example?

The chat is between only 2 users, it is not a chat room but more of a chat thread. The 2 html templates are inbox.html and thread.html

Appreciate any help!

My Django Channels code is below!

consumers.py

class ChatConsumer(AsyncConsumer):
    async def websocket_connect(self, event):
        print('connected', event)

        other_user = self.scope['url_route']['kwargs']['username']
        me = self.scope['user']
        #print(other_user, me)
        thread_obj = await self.get_thread(me, other_user)
        self.thread_obj = thread_obj
        chat_room = f"thread_{thread_obj.id}"
        self.chat_room = chat_room
        # below creates the chatroom
        await self.channel_layer.group_add(
            chat_room,
            self.channel_name
        )

        await self.send({
            "type": "websocket.accept"
        })

    async def websocket_receive(self, event):
        # when a message is recieved from the websocket
        print("receive", event)
        front_text = event.get('text', None)
        if front_text is not None:
            loaded_dict_data = json.loads(front_text)
            msg =  loaded_dict_data.get('message')
            user = self.scope['user']
            username = 'default'
            if user.is_authenticated:
                username = user.username
            myResponse = {
                'message': msg,
                'username': username,
            }
            await self.create_chat_message(user, msg)

            # broadcasts the message event to be sent, the group send layer
            # triggers the chat_message function for all of the group (chat_room)
            await self.channel_layer.group_send(
                self.chat_room,
                {
                    'type': 'chat_message',
                    'text': json.dumps(myResponse)
                }
            )
    # chat_method is a custom method name that we made
    async def chat_message(self, event):
        # sends the actual message
        await self.send({
                'type': 'websocket.send',
                'text': event['text']
        })

    async def websocket_disconnect(self, event):
        # when the socket disconnects
        print('disconnected', event)

    @database_sync_to_async
    def get_thread(self, user, other_username):
        return Thread.objects.get_or_new(user, other_username)[0]

    @database_sync_to_async
    def create_chat_message(self, me, msg):
        thread_obj = self.thread_obj
        return ChatMessage.objects.create(thread=thread_obj, user=me, message=msg)

manager

class ThreadManager(models.Manager):
    def by_user(self, user):
        qlookup = Q(first=user) | Q(second=user)
        qlookup2 = Q(first=user) & Q(second=user)
        qs = self.get_queryset().filter(qlookup).exclude(qlookup2).distinct()
        return qs

    # method to grab the thread for the 2 users
    def get_or_new(self, user, other_username): # get_or_create
        username = user.username
        if username == other_username:
            return None, None
        # looks based off of either username
        qlookup1 = Q(first__username=username) & Q(second__username=other_username)
        qlookup2 = Q(first__username=other_username) & Q(second__username=username)
        qs = self.get_queryset().filter(qlookup1 | qlookup2).distinct()
        if qs.count() == 1:
            return qs.first(), False
        elif qs.count() > 1:
            return qs.order_by('timestamp').first(), False
        else:
            Klass = user.__class__
            try:
                user2 = Klass.objects.get(username=other_username)
            except Klass.DoesNotExist:
                user2 = None
            if user != user2:
                obj = self.model(
                        first=user,
                        second=user2
                    )
                obj.save()
                return obj, True
            return None, False

models.py

class Thread(models.Model):
    first        = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_first')
    second       = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_second')
    updated      = models.DateTimeField(auto_now=True)
    timestamp    = models.DateTimeField(auto_now_add=True)

    objects      = ThreadManager()

    def __str__(self):
        return f'{self.id}'

    @property
    def room_group_name(self):
        return f'chat_{self.id}'

    def broadcast(self, msg=None):
        if msg is not None:
            broadcast_msg_to_chat(msg, group_name=self.room_group_name, user='admin')
            return True
        return False

class ChatMessage(models.Model):
    thread      = models.ForeignKey(Thread, null=True, blank=True, on_delete=models.SET_NULL)
    user        = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='sender', on_delete=models.CASCADE)
    message     = models.TextField()
    timestamp   = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'{self.id}'

views.py

class InboxView(LoginRequiredMixin, ListView):
    template_name = 'chat/inbox.html'
    context_object_name = 'threads'
    def get_queryset(self):
        return Thread.objects.by_user(self.request.user).exclude(chatmessage__isnull=True).order_by('timestamp')
        # by_user(self.request.user)

class ThreadView(LoginRequiredMixin, FormMixin, DetailView):
    template_name = 'chat/thread.html'
    form_class = ComposeForm
    success_url = '#'

    def get_queryset(self):
        return Thread.objects.by_user(self.request.user)

    def get_object(self):
        other_username  = self.kwargs.get("username")
        obj, created    = Thread.objects.get_or_new(self.request.user, other_username)
        if obj == None:
            raise Http404
        return obj

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.get_form()
        return context

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        self.object = self.get_object()
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form):
        thread = self.get_object()
        user = self.request.user
        message = form.cleaned_data.get("message")
        ChatMessage.objects.create(user=user, thread=thread, message=message)
        return super().form_valid(form)

thread.html

{% block head %}
<title>Chat</title>
http://%%20static%20'/channels/js/websocketbridge.js'%20%
{% endblock %}


    {% block content %}
    
{% for chat in object.chatmessage_set.all %} {% if chat.user == user %}
sunil
{{ chat.message }} {{ chat.timestamp }}
</div> {% else %}
sunil
{{ chat.message }} {{ chat.timestamp }}
</div> </div> {% endif %} {% endfor %} </div>
{% csrf_token %} {{ form.as_p }}
</div> </div> </div> </div> </div> {% endblock %} {% block script %} https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.js // websocket scripts - client side* var loc = window.location var formData = $("#form") var msgInput = $("#id_message") var chatHolder = $('#chat-items') var me = $('#myUsername').val() var wsStart = 'ws://' if (loc.protocol == 'https:') { wsStart = 'wss://' } var endpoint = wsStart + loc.host + loc.pathname var socket = new ReconnectingWebSocket(endpoint) // below is the message I am receiving socket.onmessage = function(e) { console.log("message", e) var chatDataMsg = JSON.parse(e.data) chatHolder.append('
  • ' + chatDataMsg.message + ' from ' + chatDataMsg.username + '
  • ') } // below is the message I am sending socket.onopen = function(e) { console.log("open", e) formData.submit(function(event) { event.preventDefault() var msgText = msgInput.val() var finalData = { 'message': msgText } socket.send(JSON.stringify(finalData)) formData[0].reset() }) } socket.onerror = function(e) { console.log("error", e) } socket.onclose = function(e) { console.log("close", e) } document.addEventListener('DOMContentLoaded', function() { const webSocketBridge = new channels.WebSocketBridge(); webSocketBridge.connect('/ws'); webSocketBridge.listen(function(action, stream) { console.log("RESPONSE:", action); }) document.ws = webSocketBridge; /* for debugging */ }) {% endblock %}


    Get this bounty!!!

    #StackBounty: #django #python-3.x #django-forms #django-views How to add multiple images to a django form asynchronously before form su…

    Bounty: 100

    Intro: I have a python Django web app where users are allowed to create posts. Each post has 1 main image and followed by extra images (max 12 & min 2) that are associated with that post. I want to let users add a total of 13 images. 1 main image and 12 extra images.

    The issue: Usually users take photos with their smart phones. which makes image size upto 10MB . with 13 images that can become 130MB form. My django server can accept a max of 10MB form. So I cannot reduce the images ServerSide

    What I want to do: I want such that when the user uploads each image to a form. The size of that image is reduced on client side and it is asynchronously saved in a temporary place on my server using Ajax. When the post is created all these images are linked to the post. So basically when the user hits submit on the post create form. Its a super light form with no images. Sounds too ambitious.. ha ha maybe

    What I have so far:

    1. I have the models/views (all django parts that create a post) without the asynchronous part. As in, if the form after all images are added is less than 10MB. My post is created with how many ever extra images
    2. I have the Javascript code that reduces the size of the images on the client side and asynchronously adds it to my server. All I need to do is give it a endpoint, which is a simple url
    3. I have a rough idea of how I plan to achieve this

    Now to show you my code

    My Models (Just the django part no asynchronous part added as yet)

    class Post(models.Model):
        user = models.ForeignKey(User, related_name='posts')
        title = models.CharField(max_length=250, unique=True)
        slug = models.SlugField(allow_unicode=True, unique=True, max_length=500)
        message = models.TextField()
        post_image = models.ImageField()
    
    class Extra (models.Model): #(Images)
        post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_extra')
        image = models.ImageField(upload_to='images/', blank=True, null=True, default='')
        image_title = models.CharField(max_length=100, default='')
        image_description = models.CharField(max_length=250, default='')
        sequence = models.SmallIntegerField(validators=[MaxValueValidator(12), MinValueValidator(1)])
    

    My views (Just the django part no asynchronous part added as yet)

    @login_required
    def post_create(request):
        ImageFormSet = modelformset_factory(Extra, fields=('image', 'image_title', 'image_description'), extra=12, max_num=12,
                                            min_num=2)
        if request.method == "POST":
            form = PostForm(request.POST or None, request.FILES or None)
            formset = ImageFormSet(request.POST or None, request.FILES or None)
            if form.is_valid() and formset.is_valid():
                instance = form.save(commit=False)
                instance.user = request.user
                instance.save()
                for index, f in enumerate(formset.cleaned_data):
                    try:
                        photo = Extra(sequence=index+1, post=instance, image=f['image'],
                                     image_title=f['image_title'], image_description=f['image_description'])
                        photo.save()
                    except Exception as e:
                        break   
    
                return redirect('posts:single', username=instance.user.username, slug=instance.slug)
    

    Now Just to keep things simple I will not add any Javascript in this question. Adding the below script tag to my form makes the image saved asynchronously to the server. You can read more about Filepond if you wish

    '''See the urls below to see where the **new_image** is coming from'''
        FilePond.setOptions({ server: "new_image/",
                              headers: {"X-CSRF-Token": "{% csrf_token %}"}}
        }); #I need to figure how to pass the csrf to this request Currently this is throwing error
    

    My plan to make it work

    Add a new model below the existing 2 models

    class ReducedImages(models.Model):
        image = models.ImageField()
        post = models.ForeignKey(Post, blank=True, null=True, upload_to='reduced_post_images/')
    

    Change the view as below (only working on the main image for now. Not sure how to get the Extra images )

    ''' This could be my asynchronous code  '''
    @login_required
    def post_image_create(request, post):
        image = ReducedImages.objects.create(image=request.FILES)
        image.save()
        if post:
            post.post_image = image
    
    
    @login_required
    def post_create(request):
        ImageFormSet = modelformset_factory(Extra, fields=('image', 'image_title', 'image_description'), extra=12, max_num=12,
                                            min_num=2)
        if request.method == "POST":
            form = PostForm(request.POST or None)
            formset = ImageFormSet(request.POST or None, request.FILES or None)
            if form.is_valid() and formset.is_valid():
                instance = form.save(commit=False)
                instance.user = request.user
                post_image_create(request=request, post=instance) #This function is defined above
                instance.save()
                for index, f in enumerate(formset.cleaned_data):
                    try:
                        photo = Extra(sequence=index+1, post=instance, image=f['image'],
                                     image_title=f['image_title'], image_description=f['image_description'])
                        photo.save()
    
                    except Exception as e:
                        break
                return redirect('posts:single', username=instance.user.username, slug=instance.slug)
        else:
            form = PostForm()
            formset = ImageFormSet(queryset=Extra.objects.none())
        context = {
            'form': form,
            'formset': formset,
        }
        return render(request, 'posts/post_form.html', context)
    

    my urls.py

    url(r'^new_image/$', views.post_image_create, name='new_image'),
    

    Any suggestions on how I can make this work

    My Templates

    {% extends 'posts/post_base.html' %}
    {% load bootstrap3 %}
    {% load staticfiles %}
    
    {% block postcontent %}
    <head>
    
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link href="https://unpkg.com/filepond/dist/filepond.css" rel="stylesheet" type="text/css"/>
        <link href="https://unpkg.com/filepond-plugin-image-edit/dist/filepond-plugin-image-edit.css" rel="stylesheet" type="text/css"/>
        <link href="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css" rel="stylesheet" type="text/css"/>
        <link href="{% static 'doka.min.css' %}" rel="stylesheet" type="text/css"/>
        <style>
        html {
            font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;
            font-size: 1em;
        }
    
        body {
            padding: 2em;
            max-width: 30em;
        }
        </style>
    </head>
    <body>
    

    Add a new Recipe

    {% csrf_token %} {% bootstrap_form form %} {{formset.management_form}}

    You must be present in at least 1 image making the dish. With your face clearly visible and matching your profile picture

    (Remember a picture is worth a thousand words) try to add as many extra images as possible (Minimum 2). People love to see how its made. Try not to add terms/language which only a few people understand. Please add your own images. The ones you took while making the dish. Do not copy images
    {% for f in formset %}

    Extra Image {{forloop.counter}}

    {% bootstrap_form f %}
    {% endfor %} <br/><button type="button" id="add_more" onclick="myFunction()">Add more images</button> <input type="submit" class="btn btn-primary" value="Post" style="float:right;"/> </form> </div> [ {supported: 'Promise' in window, fill: 'https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js'}, {supported: 'fetch' in window, fill: 'https://cdn.jsdelivr.net/npm/fetch-polyfill@0.8.2/fetch.min.js'}, {supported: 'CustomEvent' in window && 'log10' in Math && 'sign' in Math && 'assign' in Object && 'from' in Array && ['find', 'findIndex', 'includes'].reduce(function(previous, prop) { return (prop in Array.prototype) ? previous : false; }, true), fill: 'doka.polyfill.min.js'} ].forEach(function(p) { if (p.supported) return; document.write(''); }); </script> https://unpkg.com/filepond-plugin-image-edit https://unpkg.com/filepond-plugin-image-preview https://unpkg.com/filepond-plugin-image-exif-orientation https://unpkg.com/filepond-plugin-image-crop https://unpkg.com/filepond-plugin-image-resize https://unpkg.com/filepond-plugin-image-transform https://unpkg.com/filepond http://%%20static%20'doka.min.js'%20% FilePond.registerPlugin( FilePondPluginImageExifOrientation, FilePondPluginImagePreview, FilePondPluginImageCrop, FilePondPluginImageResize, FilePondPluginImageTransform, FilePondPluginImageEdit ); // Below is my failed attempt to tackle the csrf issue const csrftoken = $("[name=csrfmiddlewaretoken]").val(); FilePond.setOptions({ server: { url: 'http://127.0.0.1:8000', process: { url: 'new_image/', method: 'POST', withCredentials: false, headers: { headers:{ "X-CSRFToken": csrftoken }, timeout: 7000, onload: null, onerror: null, ondata: null } } }}); // This is the expanded version of the Javascript code that uploads the image FilePond.create(document.querySelector('input[type="file"]'), { // configure Doka imageEditEditor: Doka.create({ cropAspectRatioOptions: [ { label: 'Free', value: null } ] }) }); The below codes are exacty like the one above. I have just minimised it FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); FilePond.create(document.querySelector('input[type="file"]'), {...}); // ignore this part This is just to have a new form appear when the add more image button is pressed. Default is 3 images document.getElementById("form1").style.display = "block"; document.getElementById("form2").style.display = "block"; document.getElementById("form3").style.display = "block"; let x = 0; let i = 4; function myFunction() { if( x </body> {% endblock %}

    I have not added the forms.py as they were not relevant


    Get this bounty!!!

    #StackBounty: #python #django #caching #django-admin Is it possible to enable caching from Django admin pages?

    Bounty: 300

    I have a Django-based website at ozake.com, and I am frequently rewriting parts of the programming.

    Each time I work on it, I have to modify settings.py to disable caching.

    I am using file-based caching. Here is the relevant part of settings.py:

    CACHES = {
      'default': {'BACKEND':
     #'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
      'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
      'LOCATION': '/var/www/mysite.com/cache',
    

    When I work on the site I comment out the last two lines and uncomment the dummy cache line.

    This means SSH’ing into the site, modifying settings.py, working on the site, then re-modifying it.

    Is there any way I can make this into a check box somewhere in /admin with admin.py?

    Alternative idea: is it possible to disable caching for a visitor (me) with a specific IP address? If so, could I specify this IP address in /admin?


    Get this bounty!!!

    #StackBounty: #django #apache #amazon-web-services #mod-wsgi #amazon-elastic-beanstalk Disable health-check logging in AWS ELB Django A…

    Bounty: 50

    I have a Django application running on aws-elastic-beanstalk. I try to disable the logs caused by my health-checks. The health-checks are already routed to a seperate page.

    Elastic-beanstalk uses Apache + mod_wsgi.

    The following code is a solution that works with nginx servers. I try to create something similar for apache.

    I found out that conditional Logs are probably the appropriate way to do it with an Apache Server.

    My directory struture looks like the following

    /etc/httpd/
      - conf 
          - httpd.conf # main conf
      - conf.d 
          - wsgi.conf # virtual hosts
          - additional config files
    

    my attempt:

    files:
      "/etc/httpd/conf.d/disable_health_logs.conf":
        mode: "000644"
        owner: root
        group: root
        content: |
            SetEnvIf Request_URI "^/health/$" dontlog
            CustomLog logs/access_log common env=!dontlog
    

    The file is created but it has no effect. Neither do I see error logs nor a change in the access logs.

    In the httpd.conf there is already the following setting:

     CustomLog "logs/access_log" combined
    

    Do I need to override it?


    Get this bounty!!!

    #StackBounty: #django #session #cookies Django signed cookie session storage, replay attacks, and SESSION_COOKIE_AGE

    Bounty: 50

    As per the Django documentation, signed cookie session storage is vulnerable to a replay attack:

    Note also that while the MAC can guarantee the authenticity of the
    data (that it was generated by your site, and not someone else), and
    the integrity of the data (that it is all there and correct), it
    cannot guarantee freshness i.e. that you are being sent back the last
    thing you sent to the client. This means that for some uses of session
    data, the cookie backend might open you up to replay attacks. Unlike
    other session backends which keep a server-side record of each session
    and invalidate it when a user logs out, cookie-based sessions are not
    invalidated when a user logs out. Thus if an attacker steals a user’s
    cookie, they can use that cookie to login as that user even if the
    user logs out. Cookies will only be detected as ‘stale’ if they are
    older than your SESSION_COOKIE_AGE.

    Does this mean that:

    1. We are relying on the client-side expiration of cookies to ensure that the session data is destroyed (thus a replay attack is still possible if the cookie contents are captured before the cookie is removed by the browser), or
    2. The server detects the staleness of the data (comparing with SESSION_COOKIE_AGE and explicitly rejects data it deems as stale.

    It seems technically possible for Django to be able to determine how ‘old’ a session is without persisting this data server-side, but the docs don’t seem clear about whether or not this is being done, or is Django relying on / trusting the user’s browser to kill old cookies (and thus the session could still be replayed if the data was captured prior to its expiry).


    Get this bounty!!!

    #StackBounty: #python #sql #django #python-3.x #orm How do I use timedelta with a column in my Django ORM query?

    Bounty: 150

    I’m using Django and Python 3.7. I have the below two models …

    class Article(models.Model):
        ...
        publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, related_name="articles",)
        created_on = models.DateTimeField(default=datetime.now)
    
    class WebPageStat(models.Model):
        ...
        publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, related_name="stats", )
    
        elapsed_time_in_seconds = models.FloatField(default=0)
        score = models.BigIntegerField(default=0)
    
    class Publisher(models.Model):
       name = models.CharField(max_length=100)
    
       def __str__(self):
           return self.name
    

    I want to write a Django ORM query where given a publisher and an elapsed time in seconds (a WebPageStat record), I find all articles whose “created_on” date is not older than the elapsed time in seconds. Many have suggested using “timedelta,” in other posts, but that doesn’t seem to be working for me here …

    Article.objects.filter(created_on__lte=datetime.now(timezone.utc) - timedelta(hours=0, minutes=0, seconds=publisher__stats__elapsed_time_in_seconds))
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    NameError: name 'publisher__stats__elapsed_time_in_seconds' is not defined
    

    Can I use timedelta with SQL column logic? Otherwise how do I do this?


    Get this bounty!!!

    #StackBounty: #django #django-rest-framework #django-csrf django rest framework – session auth vs token auth, csrf

    Bounty: 50

    I have DRF set with the default settings. My ajax clients works fine with the session authentication. I want another remote server to consume the same API as the javascript clients.

    My login code is simple:

    class Login(APIView):
        def post(self, request, *args, **kwargs):
    
            user = authenticate(username=username, password=password)
    
            if user is None:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
    
            login(request, user)
            # ...
    

    The issue is when I use a client from another host, like python requests, I get a CSRF error. According to DRF docs, I think I should use a token authentication instead.

    Questions:

    1. Why do I need token authentication? The sessionid cookie is already a token, why I can’t use it both for ajax clients and software clients? Thus avoid another separate db table for the tokens.

    2. Since I do want to use only session authentication, how to enforce CSRF only for ajax clients?


    Get this bounty!!!