#StackBounty: #django #django-views #django-urls Is there a way to get a referring URL via a custom HTTP header?

Bounty: 100

I am currently using the following function to get a referring view:

def get_referer_view(request, default=None):   
    referer = request.META.get('HTTP_REFERER')
    if not referer:
        return default

    # remove the protocol and split the url at the slashes
    referer = re.sub('^https?://', '', referer).split('/')
    if referer[0] != request.META.get('SERVER_NAME'):
        return default

    # add the slash at the relative path's view and finished
    referer = u'/' + u'/'.join(referer[1:])
    return referer

If I redirected the view as a result of programmatic logic, e.g…

return HttpResponseRedirect('dashboard')

…is there a way to get the referring view without using HTTP_REFERER so that I can use that variable in the redirected view? This is not always set in the headers of the browser.

Note because the views are redirected pro grammatically, I can’t use POST to collect the data.

Perhaps its possible to set and retrieve a custom header somehow?


Get this bounty!!!

#StackBounty: #python #django #mongodb #django-rest-framework #django-views Django Rest Framework not retrieving data from my database

Bounty: 50

I’m creating an API endpoint to retrieve data from a Mongo database, in order to use it on my frontend.

On my project, i’m using two DBs: a sqlite db and the Mongo DB.

In the Mongo database, there is a collection called tst with some data in it. I created the endpoint, but after opening the api on my browser, i see no json data retrieved from the collection, as if it’s not looking in the right place.

Can someone help me find what i’m doing wrong?

Here is my model:

class tst(models.Model):
    id = models.CharField(max_length=100)
    ticker = models.FloatField()

    def save(self, *args, using=None, **kwargs):
        super(tst, self).save(*args, using='dbtwo', **kwargs)

Here is my view:

class tstList(generics.ListCreateAPIView):
    queryset = tst.objects.using('dbtwo').all()
    serializer_class = tstSerializer

Here is the serializer:

class tstSerializer(serializers.ModelSerializer):

    class Meta:
        model = tst
        fields = ('id', 'ticker', )

And the url:

path('tst/', views.tstList.as_view()),


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!!!