I'm developing a reservation system REST api in Django with a relatively simple model that will determine if a user has a valid membership in order for them to reserve a certain item. When creating a reservation, I have a simple validator written like this:
def validate_member(value):
"""
Validator for a user in a reservation. Will throw a ValidationError if the user does not have an
updated membership.
"""
if not valid_membership(value):
raise ValidationError("User does not have a valid membership!")
This validation is run on the foreign key field in the reservation table, which is written as such:
# The gear item in the reservation
gear_item = models.ForeignKey(Entry,
on_delete=models.SET_NULL,
null=True,
help_text="The gear item being reserved.",
validators=[validate_entry]
)
The serializer for this model is written as a ModelSerializer, like such:
class ReservationSerializer(serializers.ModelSerializer):
class Meta:
model = Reservation
fields = "__all__"
This design works fine for queries in the REST API, but fails for any modifications in the admin console, with the error: 'int' object has no attribute 'rentable'
It seems that validating a foreign key in the admin console passes the primary key integer into the value parameter of the validation function, while the REST API passes in the entire object. Is there a workaround for this, or should I expect to not use the admin console at all due to this limitation?
Best solution/work around for this would be overriding your admin console's form.
I think this code snippet will be enough for you to handle your specific field and it's validation.
Related
Within an app for an online shop I have two simple models for products and deliveries:
class Product(model.models):
delivery = models.ForeignKey(Delivery, on_delete=models.CASCADE)
class Delivery(model.models):
published = models.Datefield()
I am using the build-in Django admin.
class ProductInline(admin.TabularInline):
model = Product
#admin.register(Delivery)
class DeliveryAdmin(admin.ModelAdmin):
inlines = [ProductInline,]
To increase robustness of the app it is very important, that products can't be changed as soon as the related delivery has been published to the customer. So on very attempt to change a product, I need to do some validation to check if the Delivery has been published. Things I have tried:
Create fieldset for InlineAdmin with custom clean()method
Custom clean() method on the model instance
These approaches don't work, though. When implemented, I loose the ability to edit the entire delivery model from the admin panel (I am trying to only limit edits of products). This is because clicking the save Button in the admin Panel will automatically call save() and clean() on the products regardless of weather or not the products were changed.
Has someone encountered a similar problem before?
Maybe, you need to override the form?
class ProductInlineForm(forms.ModelForm):
def clean(self):
# your validation.
# here you can raise ValidationError
return super().clean()
class ProductInline(admin.TabularInline):
form = ProductInlineForm
model = Product
https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#overriding-the-clean-method
I've written my first application Django 2.0.
Everything is working fine and the application is almost ready when I realized to replace id primary key field from default integer type to UUID to make database entry more secure.
When I searched for this how to change id of user table to UUID I got many tutorials extending AbstractBaseUser.
Here is I have written own User model.
account/models.py
class User(AbstractBaseUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
But I'm confused more with examples on different sources.
Every example is adding few more fields in extended model like
first_name
last_name
is_staff
is_admin
active
and functions as
def get_fullname(self):
def get_shortname(self):
etc.
I think all these fields and functions are there by default in AUTH_USER_MODEL.
Does extending AbstractBaseUser overwrites AUTH_USER_MODEL and it is required to add all fields which is there by default?
also, I'm using settings.AUTH_USER_MODEL as foreign key in different models. Should It be replaced by account.User model?
I'm also using django-allauth plugin to enable login using the social network and use email only for authentication. Do I require to add email field in the extended model with unique=True?
Django AbstractBaseUser provides only following fields: password, last_login, is_active. So if you are using custom User model inherited from AbstractBaseUser you need to define all other fields such as email manually.
As another part of question just adding AUTH_USER_MODEL = 'users.User' to your settings.py file should make everything works without replace code in your project.
UPD
If you need field like first_name, last_name, etc. to be includet to the model you can use AbstractUser instead of AbstractBaseUser.
As the Django documentation indicates, it's difficult to extend the User table after-the-fact, and not recommended at all for apps. A better way is to create an auxiliary table which has a 1:1 relationship with the user-id. Leave Django's user-table alone and just use this other table to pony-up to it.
The "Django Annoying" project, at https://github.com/skorokithakis/django-annoying#autoonetoonefield, has some very useful "juice" to make this much easier: an AutoOneToOneField. Whereas Django's foreign-key field will throw an error if an record doesn't exist, this field will automagically create one on-the-fly, thereby side-stepping the entire issue. (The documentation page linked-to above shows exactly how this is done.)
I'm migrating something from an old PHP/apache server to Django. I'm a bit stumped with the 'ModelForm'.
As far as I understand, a "Model" is the abstraction for persistent elements in my website/server - specifically this is something stored physically, say in a database, and defines the fields (read columns) in the DB.
I started moving the authentication part of the site, and discovered models, and specifically the User model (I made an empty User inheriting AbstractUser just in case I will ever need to extend things). Now I want to create a simple two field form, to authenticate login.
The form:
Username (which is a field of User, by default)
Password (Which is not).
Even the 'Username' needs a redefinition in the model form. So my questions:
What is the advantage of the model form (over just a form)? - seems like you're redefining fields anyway, and obviously sometimes adding fields on top of the model.
Specifically for authentication, I probably need to store my salted hash associated with the user somehow, compare my password using that and retrieve the user object. This is something I find very hard to find in the Django docs - they just have too much written on authentication, and not one full code example. Do I put this in the "validate" method of form, retrieving there an object and storing it in a session or something?
If there is a deeper relation between a model form and the associated model, I would like to know as well.
Simple django forms and modelforms have quite differences.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
The above example illustrates that you don't have to write any form field in here. The model form will itself create a form which is based on the attributes provided in the model ('Article' in this example).
If you create a simple django form then it would be something like:
class ArticleForm(forms.Form):
some_field = forms.CharField(some_attrs)
...
The django User model provides you everything you need for authentication. When you want to create users just import django.contrib.auth.models.User and use create method to create objects. Then when you want to authenticate a user use authenticate method.
from django.contrib.auth import authenticate, login
def user_login(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
# after authentication login the user or set cookies or modify the session or some other action can be taken
return HttpResponse("Some response or use render for html page")
username and password will be coming from your post request.
If you want to extend default Django user model you can use django user model as onetoonefield in your extended model.
class AppUser(models.Model):
user = models.OneToOneField(User)
... # other custom fields
I have a model called Lead which represents my possible future_customer.
In order to update a boolean field called is_approved in this model, I'm sending an email to the Lead's email ID along with a URL and this URL will take you to a page in my website where it asks for Approval.
How do I deal with permissions in Django Rest framework views? There is no django user associated with Lead model and I cannot use any authentication related classes.
Obscured url along with AllowAny permission is good enough?
What generally happens in a normal scenario for validation of emails is that they generate a unique token for the corresponding email. Then they when the user clicks on the email. He is taken to a page where there could be form submit which takes to a POST page or just validates directly.
The only security is that the unique id is just unique and there is a very rare chance for someone generate those id's via brute-force. That's the only security. You can add a expire also that makes the link valid only for few days.
You find the corresponding email associated with the same and update is_approved field accordingly.
Your model and view should look something like this.
class Lead(models.Model):
email = models.EmailField()
unique_id = models.CharField(default=uuid.uuid4)
is_approved = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('lead_verification', kwargs={'unique_id': self.unique_id})
class LeadVerificationView(APIView):
def post(self, unique_id):
lead = Lead.objects.get(unique_id=unique_id)
lead.is_approved = True
lead.save()
I need to create custom users in my app.
In the example given in the doc
class CustomUser(models.Model):
user = models.OneToOneField(User)
#custom fields
a user must exists before creating a CustomUser.
What I want to do is to create automatically a User when I create a CustomUser.
In the CustomUser admin (only visible by the superuser), I'd like to have only the custom fields and a few fields from the User model, as well as some form to allow the superuser to change the password for existing instance.
Anybody could help?
The first part of your question is easy, you can use a signal:
def create_custom_user(sender, instance, created, **kwargs):
if created:
custom_user, created = CustomUser.objects.get_or_create(user=instance)
post_save.connect(create_custom_user, sender=User)
As for the second part, theres already a change password form in the admin. To filter out the displayed fields you can create a CustomUserAdmin and register it together with the model. It's pretty self explaining in the django docs.
django docs: list_display