skip to Main Content

I’m creating a simple blog with a Django backend using MongoDB to store blog posts and their metadata.
Everything worked find when I was testing with a local mongodb instance, but when I switched to an atlas hosted database I started getting the following error.
error

The current Post model is
`

class Post(models.Model):

 _id = models.UUIDField(
    primary_key=True, default=uuid.uuid4, editable=False)
 title = models.CharField(
    max_length=50, help_text='Post title. equivalent to obsidian file name')
  publish_date = models.DateField()
  last_edited = models.DateField(auto_now=True)
  content = models.TextField(blank=False)
  summary = models.TextField(blank=True)
  tags = models.CharField(max_length=20, blank=False)
  choices = [
    ('published', 'published'),
    ('draft', 'draft'),
    ('private', 'private')
  ]
  status = models.CharField(
    choices=choices, default='published', max_length=20, blank=False,)

  class Meta:
    pass

  def get_absolute_url(self):
    return reverse('post', args=[self._id])

  def __str__(self):
    return self.title

And the associated view

class PostDetailView(generic.DetailView):
    model = Post

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

        # context['post'].tags = context['post'].tags.split(',')
        context['post'].content = markdown.markdown(context['post'].content)

        return context

To debug I overrode the get_object method as follows:

      
      def get_object(self, *args, **kwargs):
          kwargs = self.kwargs
          kw_id = kwargs.get('pk')

          all_results = Post.objects.filter()
          print(all_results.first()._id == str(kw_id))
          result = Post.objects.get(_id=str(kw_id))
          print("result:", result)

          return result

assuming there is only one test post in the DB, all_results = Post.objects.filter() returns the post, but some of its element (e.g. all_results.first().content are None even though it is populated in the DB.
the main problem is that when trying to filter or get based on the value of the _id field no results are returned even though print(all_results.first()._id == str(kw_id)) outputs true.
Any ideas as to what might be causing this, please?

Edit:
Since the posts are added from somewhere else (an obsidian plugin) I ran a test to compare the posts created from the admin page (which work properly) to those created by the plugin, and it seems that the id field which is created using typsscripts’ uuid.v4() produce a mongodb string _id field whereas the posts created in the admin page end up with a BinData type. How can these be made to match ?

2

Answers


  1. Chosen as BEST ANSWER

    I ended up figuring it out. The issue was the type compatibility of the _id field. On the typescript side I generate the _id using mongoDB's new ObjectId(). On the Django side I convert the _id received as a string from get_absolute_url() to a bson.objectid.ObjectId class before doing the filtering. I also changed the model to the following (switched to djongo fields)

    from djongo import models
    
    class Post(models.Model):
    
        _id = models.ObjectIdField(primary_key=True, editable=False)
        title = models.CharField(
            max_length=50, help_text='Post title. equivalent to obsidian file name')
        publish_date = models.DateField()
        last_edited = models.DateField(auto_now=True)
        contents = models.TextField(blank=False)
        summary = models.TextField(blank=True)
        # tags = models.CharField(max_length=20, blank=False)
        tags = models.JSONField(max_length=20)
        choices = [
            ('published', 'published'),
            ('draft', 'draft'),
            ('private', 'private')
        ]
        status = models.CharField(
            choices=choices, default='published', max_length=20, blank=False,)
    
        objects = models.DjongoManager()
    
        class Meta:
            pass
    
        def get_absolute_url(self):
    
            return reverse('post', args=[self._id])
    
        def __str__(self):
            return self.title
    
    

    Now the types are consistent everywhere and the queries are successful.


  2. all_results.first()._id will return the _id and if you are comparing it with id that is not same with it will return None.

    You can do:

    def get_object(self, *args, **kwargs):
          kwargs = self.kwargs
          kw_id = kwargs.get('pk')
    
          all_results = Post.objects.filter(._id=str(kw_id))
          result = all_results.first()
          print("result:", result)
          return result
    

    With that, you will have access to the first data from the DB.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search