Equality of Django's Q objects

时间:2017-12-18 08:31:32

标签: python django django-models

I am trying to compare django's Q objects which are composed in the exact same way.

But despite all children and relations between them being same, they aren't deemed equal.

https://stackoverflow.com/questions/40526476/using-external-library-with-angular-cli

This is posing problems in my unit tests where I build up filters for my querysets using Q objects.

Why are the two Q objects not equal?

I am using Django 1.11.

2 个答案:

答案 0 :(得分:4)

Django <= 1.11.x does not implement from django.db.models import Q $ q1 = Q(a=1) & Q(b=1) & Q(c=1) $ q2 = Q(a=1) & Q(b=1) & Q(c=1) $ q1 == q2 $ False method for Q objects. As can be seen here.

Django >= 2.0 implements __eq__ method for Q objects. Code.

So it is not possible to directly check the equality of two Q objects before Django 2.0.

But it is possible to write a simple function that checks the equality of Q objects. We can directly use the code from the repo.

__eq__

So, for older versions of Django we can do:

def compare_q(q1 , q2):
        return (
            q1.__class__ == q2.__class__ and
            (q1.connector, q1.negated) == (q2.connector, q2.negated) and
            q1.children == q2.children
        )

答案 1 :(得分:0)

我基于xssChauhan的answer来处理您嵌套Q对象的情况:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <poll.h>

#define PORT "3838" //port being connected to 
#define MAXLEN 800
#define BACKLOG 10 //number of pending connections to be held in queue

//format of html page 

char header []= 
"HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html>\r\n"
"<html>\n"
"<head>\n"
"<title>Web-Based Remote Command Server</title>\r\n"
"</head>\n"
"<body>\n\n";
char input []=
"<form action= \"/run\" method= \"GET\"> \n"
"Command: <input type=\"text\" size=\"100\" name=\"command\">\n"
"<input type=\"submit\" value=\"Run\">\n"
"</form>";
char output []=
"<p>Command that was run and testing this:</p>\n"
"<pre>Your server will include the command that was just run here.</pre>\n\n"
"<p>Standard Output:</p>\n""<pre>Your server will include the stdout results here.</pre>\n\n";
char outputerr[]=
"<p>Standard Error:</p>\n"
"<pre>Your server will include the stderr results here.</pre>\r\n\r\n"
"</body>\r\n""</html>\r\n";

char *buff = header; 

void sigchld_handler(int s)
{
    (void)s; // quiet unused variable warning

    // waitpid() might overwrite errno, so we save and restore it:
    int saved_errno = errno;

    while(waitpid(-1, NULL, WNOHANG) > 0);

    errno = saved_errno;
}


void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

char *parse(char *command){
    char * newCommand = (char *) malloc(sizeof(char)*50);
    int tgt = 0;
     newCommand = strtok(command, " ");
    //printf("%s\n", newCommand);
     newCommand = strtok(NULL, "/run?command= ");
    //printf("%s\n", newCommand);
     for(int src = 0; src< strlen(newCommand); src++){
        if(newCommand[src] == '+')
        {
            newCommand[src] = ' ';
        }
        else if(newCommand[src] == '%')
        {
            newCommand[src] = ' ';
        }
        else if(newCommand[src] == '7')
        {
            newCommand[src] = ' ';
        }
        else if(newCommand[src] == 'C')
        {
            newCommand[src] = '|';
        }


    }

     return newCommand;
}

char * execution(char *command){
    //printf("yo:%s\n",command );

  int piper[2];
    size_t len = 0;
    pipe(piper);
  char* output =  malloc(1000 * sizeof(char));
    memset(output, '\0', 1000* sizeof(char));
    pid_t pid = fork();
    if(pid != 0)// parent
        {
            wait(NULL);
            close(piper[1]);
      int n = sizeof(output);

            struct pollfd * poll_fd = malloc(sizeof(struct pollfd));
             poll_fd->fd = piper[0];
             poll_fd->events = POLLIN;

            //wait(NULL);
      //printf("done\n");
            //printf("AAA %s", output);
            if(poll(poll_fd, 1, 0) == 1){ // pipe data check
            read(piper[0], output, 1000);
            }
            //printf("the command is %s\n", output);
         //read(&output,output, piper[0]);
        // printf("%s\n",piper[0]);
            // dup2(piper[1],1);
            // close(0)
        }
        else{

            //dup2(piper[1], 1);
            //printf("run : %s", command);

            close(1);
            dup(piper[1]);
            //close(0);
            execlp(command, command, NULL);
        exit(1);
        }
 // dup2 execute and print it out in parent

                // if(*(commands+1)!=NULL) // redirect stdout as long as were not at the last row
                // {
                //  dup2(piper[1],1);
                //  close(piper[0]);
                // }
                return output;
}

int main (void){
    int sockfd;
    int new_fd; 
    struct addrinfo hints;
    struct addrinfo *serverinfo; 
    struct addrinfo *p;
    struct sockaddr_storage client_addr;
    socklen_t addrsize;
    struct sigaction sa;
    int yes = 1;
    char s[INET6_ADDRSTRLEN];
    int status;

    memset(&hints, 0, sizeof hints); //makes struct empty 
    hints.ai_family = AF_UNSPEC; //IPv4 or v6 
    hints.ai_socktype = SOCK_STREAM; //TCP type need 
    hints.ai_flags = AI_PASSIVE; //Fill in IP for us 


    //if can't get address info print error 
    if((status = getaddrinfo(NULL, PORT, &hints, &serverinfo)) != 0){
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        return 1;
    }


    for(p = serverinfo; p != NULL; p = p->ai_next){
        if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
            perror("server: socket");
            continue;
        }

        if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
            perror("setsockopt");
            exit(1);
        }

        if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    freeaddrinfo(serverinfo);

    if(p == NULL){
        fprintf(stderr, "server: failed to bind\n");
        exit(1);
    }

    if(listen(sockfd, BACKLOG) == -1){
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections....\n");

    while(1){
        addrsize = sizeof client_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &addrsize);
        if(new_fd == -1){
            perror("Did not accept");
            continue;
        }

        inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
        printf("server: got connection from %s\n", s);

        if(!fork()){
            close(sockfd);
            int bufsize = 1024;

            char *buffer = malloc(bufsize);
            recv(new_fd, buffer, bufsize, 0);
            send(new_fd, header, bufsize, 0);
            //printf("%s\n", buffer);
            //printf("%s\n", parse(buffer));
            //printf("%s\n", execution(parse(buffer)));
        //int length = strlen(output);
        //output [length + 1] = execution(parse(buffer));

            //write(new_fd, "HTTP/1.1 200 OK\n", 16);
            //write(new_fd, "Content-length: 46\n", 19);
            //write(new_fd, "Content-type: text/html\n\n", 25);
            //write(new_fd, "<html><head>\n<head>\n<title>The CAvengers Web Page</title>\n</head>\n</html>", 46);

            if(send(new_fd, execution(parse(buffer)), 1000, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);
    }

    return 0;


}