How can I encrypt <int:pk> inside my URLs? - python

I think it's a dumb question, but I can't solve this problem anyway. I'm building a simple card game with chatrooms in Django. When a mod creates a room, to enter this room you need to use the following URL:
cardgame/room/<int:pk>
where inside of <int: pk> is replaced by the id of the room created. My problem is that some random user could enter the room of id=x just using a link like cardgame/room/x without being invited. I wanted to encrypt the id number whenever a room is created, just like when you create a Google meet call but I dont know how to this using Django/Python.
How can I do this?

Possible duplicate of
Using a UUID as a primary key...
import uuid
from django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
This changes the default behaviour of django models, which are creating id as an AutoField. Either you can do this or add an additional uuid field

What about adding a UUID field to your model to create a universally unique identifiers and then using that as the path variable instead?
Something like this:
class Room(models.Model):
unique_id = models.UUIDField(default=uuid.uuid4, unique=True)

Related

Django AutoSlugField not considering soft deleted instances by Django Safe Delete

In our model we have a name and slug fields. This is how it looks like:
class MyModel(CommonInfo, SafeDeleteModel):
name = models.CharField(_('Name'), max_length=255, null=True, blank=True)
slug = AutoSlugField(_('Url'), populate_from='name', unique=True,)
For the slug field we generate an unique slug every time our model is saved.
We are also using Django Safe Delete library to soft delete our model:
Django Safe Delete
Django Autoslug
That means that for example if we create a new instance of our model with Name "My Model" it will auto generate a slug that will look like this: "/my-model".
Now let's say we "soft delete" this instance with the slug "/my-model". In our database there will be a property deleted which contains the date when the model was deleted. We don't show this one in our application, it is completely ignored (because it is soft deleted, that's fine).
The problem is that next time we create another one with the same name "My Model" it will auto generate the slug "/my-model" again, not considering that there is already one (which is soft deleted) with the same name and slug. We would need something like "/my-model-1" or whatever that is unique.
We are missing the connection between the autoslug and the safe-delete libraries, somehow the autoslug needs to know that there might be soft deleted ones and consider them when generating the unique slug.
Any help would be really appreciated and please consider that we are totally new in Django / Python.
if this doesn't work, our workaround will be generating the slug using 2 fields (name & id). It will generate a slug that will look like this: "/my-model/12345" and will be always unique since id is unique.
I think we found it.
We needed to create a new Manager that can see all the instances, even the soft deleted ones:
class MyModelAllManager(SafeDeleteManager):
_safedelete_visibility = DELETED_VISIBLE
Then in our model we pass it to the AutoSlugField function:
class MyModel(CommonInfo, SafeDeleteModel):
# We don't know why but it only works if we create a variable and assign the Manager to it. It doesn't work if we pass the Manager directly to the AutoSlugField function.
all_objects = MyModelAllManager()
name = models.CharField(_('Name'), max_length=255, null=True, blank=True)
slug = AutoSlugField(_('Url'), populate_from='name', unique=True, manager=all_objects)
That does the magic.

Django Two Model Fields, same DB Column

We are trying to work with legacy DB Tables that were generated outside of Django and are not structured in an ideal way. We also can not modify the existing tables.
The DB uses the same user ID (pk) across all the tables, wether or not there is a record for that user ID. It also uses that ID as a PK on the other tables, rather than rely on them to auto increment their own IDs.
So imagine something like this below:
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
class User(models.Model):
user_id = models.IntegerField(primary_key=True)
class UserTypeA(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
class UserTypeB(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
What we thought of creating a relationship between Items and UserTypeA (as well as UserTypeB) is to create another field entry that uses the same column as the user_id.
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
user_type_a = models.ForeignKey('UserTypeA', db_column='UserID')
user_type_b = models.ForeignKey('UserTypeB', db_column='UserID')
This unfortunately returns a "db_column is already used" type error.
Any thoughts on how to better approach the way what we're trying to do?
A detail to note is that we're only ever reading from this databases (no updates to), so a read-only solution is fine.
Thanks,
-RB
I've solved a similar problem with this (this code should be put before the definition of your Model):
from django.db.models.signals import class_prepared
def remove_field(sender, **kwargs):
if sender.__name__ == "MyModel":
sender._meta.local_fields.remove(sender.myFKField.field)
class_prepared.connect(remove_field)
(Tested in Django 1.5.11)
Django uses local_fields to make the CREATE TABLE query.
So, I've just attached the signal class_prepared and check if sender equals the class I was expecting. If so, I've removed the field from that list.
After doing that, the CREATE TABLE query didn't include the field with same db_column and the error did not ocurr.
However the Model still working properly (with manager methods properly populating the removed field from local_fields), I can't tell the real impact of that.

Proper way to log Django User activity

What's the proper way to log user activity in Django?
For example let's say a user has Groups, and I'd like to keep a record of when Object1 has been added or removed.
The method that comes to mind is to create a new record every time and pull the latest record but this feels wrong (and causes some filtering problems, eg: you can't just filter on is_member=True since you'll get stale results). Is there a proper way to log these in Django?
You can use django-auditable-models for that. It will hook in the django workflow, and will avoid that you have to write all logic yourself.
You can use loggers in Django.
https://docs.djangoproject.com/en/1.8/topics/logging/#topic-logging-parts-loggers
To log something like that I recommend you to create an core app with a TimeStampModel model:
from django.db import models
from django.utils.timezone import now
class TimeStampModel(models.Model):
"""
TimeStampModel class allows us to follow creation and update of each inherit instance
"""
created_at = models.DateTimeField(auto_now_add=now(), editable=False)
updated_at = models.DateTimeField(auto_now=now(), editable=False)
class Meta:
abstract = True
Now, inherit each models from TimeStampModel that you want to record creation or update date.
E.g:
from django.db import models
from core.models import TimeStampModel
class Token(TimeStampModel):
uuid = models.CharField(max_length=255, primary_key=True)
# ...
You can also add a delete attribute (Boolean) to realize logical delete. And the last update, will be the date of deletion.
Two Scoops of Django 1.8 recommends also this practice.

Designing models in django

I'm working on my first django project that involves a student gradebook. Starting small, I'm just working on an app where teachers can upload students (student information - name and email address) and organize them into courses. My models so far are:
class Course(models.Model):
course_name = models.CharField(max_length=20, default='Course')
def __unicode__(self):
return self.course_name
class Student(models.Model):
course = models.ForeignKey(Course)
name_text = models.CharField(max_length=40, default='First Last')
email_address = models.EmailField(max_length=40, default='address#address.com')
def __unicode__(self):
return self.name_text
However, I'm not sure if the Course class is needed. I didn't think much of it, until I tried to create my first form where a user adds a student to the database. I had tried:
class StudentForm(forms.ModelForm):
class Meta:
model = Student
fields= ('name_text',)
But this didn't work. I would get an error saying that the course field could not be null (null value in column "course_id" violates not-null constraint). So I modified to: fields ('course', 'name_text,). That worked.
This is what got me wondering if the Course class would actually be necessary. Ultimately I would like to be able to upload a text file with student names, parse the text to get the names (and email addresses) and create instances of the students. Only then would I assign the students to a course. But I get the feeling that the way I have my model setup right now will always insist that the student is assigned a course.
Should the class Course be kept?
If there is a 1-n relationship by student-course (many students in one course, a student in only one course) it's completely right.
Having a CharField instead that saves the course_name would eventually lead to inconsistencies (see db normalization, too), e.g. start off like this:
name_text | course_name
-----------------------
chris | cs-101
doug | cs-101
now cs-101 is renamed to cs-101-old and cs-101 is a new course with different topics. The db however still says we are both in new "new" course. If you have a ForeignKey to Courses you just change one value and the values in the students table change as well, since they are just pointers.
If you want the course to be optional just add a null=True to your ForeignKey declaration.
course = ForeignKey(Courses, null=True)

Best way to create a more complex model autofield in django?

I would like to have a field in my model that auto creates a unique primary key for each record.
I've been using:
models.AutoField(primary_key=True)
But this generates simple integer incremented ID's.
What I'd really like is some sort of random 16 digit alphanumeric primary key that is generated automatically and guaranteed to be unique.
What is the best way to implement this?
egreene's answer is sufficient, but if you'd like to have more control over your models' UUIDs you can define an abstract base class that automatically assigns a unique UUID using Python's built-in function.
import uuid
from django.db import models
def make_uuid():
"""Return UUID4 string."""
return str(uuid4())
class UUIDModel(models.Model):
uuid = models.CharField(
editable=False, max_length=36, db_index=True,
unique=True, default=make_uuid
)
class Meta:
abstract = True
class RealModel(UUIDModel):
name = models.CharField(max_length=36)
def do_something(self):
pass
The UUIDModel abstract base class could also easily be used as an ingredient in other mix-in abstract classes, letting you mix and match different attributes when making new models.
You want to create a UUID field. The extension here django-uuidfield, https://github.com/dcramer/django-uuidfield should work.
After installing with pip install django-uuidfield, you can add the field like so:
from uuidfield import UUIDField
class MyModel(models.Model):
uuid = UUIDField(auto=True)
Disclaimer: the code is from the github README.

Categories

Resources