3

I'm working with the built-in Django User model. This is my serializers.py:

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('username', 'password', 'email', )

This is my view:

class HomePageView(TemplateView):
    template_name = "home.html"

    def get_context_data(self, **kwargs):
            context = super(HomePageView, self).get_context_data(**kwargs)
            return context

class user_list(APIView): #called when I go to the /CMS/users URL 
    """
    List all users, or create a new user.
    """
    serializer_class = UserSerializer
    def get(self, request):
        users = User.objects.all()
        serializer = UserSerializer(users, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = UserSerializer(data=request.DATA)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

and this is home.html:

<html ng-app="notesApp">
<body ng-controller="MainCtrl as ctrl">
        <form ng-submit="ctrl.add()" name="myForm">
            <label>Username</label>
            <input type="text" name="uname" ng-model="ctrl.user.username" required> 

            <label>Password</label>
            <input type="password" name="pwd" ng-model="ctrl.user.password" required>

            <label>Email</label>
            <input type="email" name="mail" ng-model="ctrl.user.email" required> 

        <input type="submit" value="Submit" ng-disabled="myForm.$invalid"> 
        </form>
    </div>

and this is the JS:

angular.module("notesApp", [])
    .controller("MainCtrl", ["$http", function($http) {
    var self = this;
    self.users = {}
    var fetchUsers = function() {
        // the line below gets the list of all users
        return $http.get("/CMS/users").then(function(response) {
        self.users = response.data;
        }, function(errResponse) {
        console.error("Error while fetching users.");
        });
    };

    fetchUsers();

    self.add = function() {
        $http.post("/CMS/users", self.user).then(fetchUsers);
        console.log("User clicked submit with ", self.user);
    };
    }]);

I used the form and successfully created a user (I used a valid username, email and password). I tried to recreate a user using a username which already exists. When I clicked the "Submit" button on the form, it returned a 400 error in the log (as predicted) because Django does not allow a new user to be created if the username already exists. Now, django.admin.models.AbstractModel returns an error which says that the username already exists:

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    """
    An abstract base class implementing a fully featured User model with
    admin-compliant permissions.

    Username, password and email are required. Other fields are optional.
    """
    username = models.CharField(_('username'), max_length=30, unique=True,
        help_text=_('Required. 30 characters or fewer. Letters, digits and '
                    '@/./+/-/_ only.'),
        validators=[
            validators.RegexValidator(r'^[\w.@+-]+$',
                                      _('Enter a valid username. '
                                        'This value may contain only letters, numbers '
                                        'and @/./+/-/_ characters.'), 'invalid'),
        ],
        error_messages={
            'unique': _("A user with that username already exists."),
        })

Is there a way for me to display the "A user with that username already exists" with AngularJS on the front-end?

Edit: I changed the self.add() function to this:

self.add = function() {
    $http.post("/CMS/users", self.user)
    .error(function(data, status, headers, config) {
        console.log(data);
     })
    .then(fetchUsers);
};

and then when I tried to create a user using a username which already exists, this gets logged:

Object {username: Array[1]}
   username: Array[1]
     0: "This field must be unique."
     length: 1
     __proto__: Array[0]
  __proto__: Object

1 Answer 1

2
$http.post("/CMS/users", self.user).then(fetchUsers).catch(function(response){
  //here you can manipulate the response from the server and display the message
});

Actually .. per the documentation for $http, you should handle:

.error(function(data, status, headers, config) {
  // called asynchronously if an error occurs
  // or server returns response with an error status.
 })

The answer to your question bellow is that it depends. If the result is always something like : {property:[]} then you could do:

for(prop in data){
  if(data.hasOwnProperty(prop)){
     var messages = data[prop];
     // now you have the messages array and you can display them.
  }
}

Otherwise if the result differs, you're stuck with handling each case.

Edit:

Using hasOwnProperty is a best practice to ensure that we're not grabbing properties from the prototypical inheritance chain: more details - basically make sure you're not grabbing an inherited property

Sign up to request clarification or add additional context in comments.

4 Comments

what I did was: self.add = function() { $http.post("/CMS/users", self.user).error(function(data, status, headers, config) { console.log(data); }).then(fetchUsers);}; Now, when I try to create a user using a username which already exists, this gets logged: Object {username: Array[1]}... so it does return the error message. Is there any way for me to generically access the actual error message? What I mean is, sometimes the error might be: {username: Array[1]}, sometimes it might be: {email: Array[1]}. Is there a way for me to access all the actual error messages in a list of strings?
I have updated my question (see the 'Edit' section at the bottom of my question). It turns out that rather than Django passing "A user with that username already exists." to the front-end, it passes "This field must be unique." I'm not sure where Django is getting the "This field must be unique." string from but I'm hoping it is possible that I can change it to "A user with that username already exists. Please try a different username." or something along those lines.
@sirocco ignore my comment above, I think I should ask it an entirely new question since your response did answer the initial question. On a side note, why do we need the "if(data.hasOwnProperty(prop))" statement? Since we are already iterating through "for (prop in data)", isn't it a given that data.hasOwnProperty(prop) is true?
I updated my answer in regards to hasOwnProperty - I'm not familiar enough with Django to help with the other question :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.